Using streams().reduce to build a string from ArrayList<Integer>?

Viewed 729

In JavaScript we can build a string with other types using reducer (e.g. num to string):

const string = [1,2,3,4,5].reduce((acc,e) => acc += e, "") //"12345"

In Java, this pattern is not as easy when building a string from other types:

ArrayList<Integer> arrayListOfIntegers = (ArrayList<Integer>) Arrays.asList(1,2,3,4);
String string = arrayListOfIntegers.stream().reduce("", (String acc, Integer e) -> acc += e); // acc += e throws error

The error is:

"Bad return type: String cannot be converted to integer"

Is this pattern not possible in Java?

5 Answers

In Java, you can simply collect the Stream using Collectors.joining

import java.util.Arrays;
import java.util.List;
import java.util.stream.Collectors;

public class Main {
    public static void main(String[] args) {
        List<Integer> arrayListOfIntegers = Arrays.asList(1, 2, 3, 4);
        String str = arrayListOfIntegers.stream().map(String::valueOf).collect(Collectors.joining());
        System.out.println(str);
    }
}

Output:

1234

Your are trying to reduce a list of Integers to a String. First map those Integers to Strings and then reduce:

List<Integer> list = Arrays.asList(1,2,3,4);
String value = list.stream()
                   .map(String::valueOf)
                   .reduce("", String::concat);

Instead of (acc,e) -> acc+e you could use String::concat. Also, the type is not compulsory in the lambda expression.

I suppose the best way is using Collectors.joining provided by @Thomas and @Arvind Kumar Avinash. But as a alternative solution I can suggest to use collect method and StringBuilder class, it doesn't generate new String object every time as in reduce case:

List<Integer> list = Arrays.asList(1,2,3,4);
String value = 
       list.stream()
           .collect(StringBuilder::new, StringBuilder::append, StringBuilder::append)
           .toString();

I suggested this code:

public static void main(String[] args) {
    List<Integer> arrayListOfIntegers = Arrays.asList(1,2,3,4);
    String string = arrayListOfIntegers.stream().reduce("",(sum,elm)-> sum += elm.toString(),(sum1,sum2) -> sum1+sum2);
    System.out.println(string);
}

Among few other options, here is my contribution, when you have list of int i.e primitive values please use [IntStream][1] here is how i have tried to do it. rangeClosed is inclusive of the last number. mapToObj is a intermediate and collect is a terminal operation.

import java.util.Optional;
import java.util.stream.Collectors;
import java.util.stream.IntStream;

public class SampleIntStream {
    public static void main(String[] args) {
        System.out.println(getComposedString(1, 5));
    }

    public static String getComposedString(int from, int to) {
        return IntStream
                .rangeClosed(from, to)
                .mapToObj(String::valueOf)
                .collect(Collectors.joining());
    }
}
Related