Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Flattening a List of List to a List with Java 8 stream API

I have the following code which could be much simpler using Java 8 stream API:

List<List<String>> listOfListValues;
public List<String> getAsFlattenedList() {
        List<String> listOfValues= new ArrayList<>();
        for (List<String> value: listOfListValues) {
            listOfValues.add(String.valueOf(value));
        }
        return listOfValues;
    }

I searched for a solution on SO and found this:

listOfListValues.stream()
        .flatMap(List::stream)
        .collect(Collectors.toList());

But this doesn't do the same what I want.

like image 920
Twi Avatar asked Nov 28 '18 09:11

Twi


People also ask

How do you flatten a stream List?

The standard solution is to use the Stream. flatMap() method to flatten a List of Lists. The flatMap() method applies the specified mapping function to each element of the stream and flattens it.

How do you flatten an array in Java?

Create an empty list to collect the flattened elements. With the help of forEach loop, convert each elements of the array into stream and add it to the list. Now convert this list into stream using stream() method. Now flatten the stream by converting it into array using toArray() method.

How do you use flatMap in Java 8?

Use the flatMap() method when the mapper function is producing multiple values for each input value. Use the map() method when the mapper function is producing single values for each input value.

Can we convert stream to List in Java?

Stream class has toArray() method to convert Stream to Array, but there is no similar method to convert Stream to List or Set. Java has a design philosophy of providing conversion methods between new and old API classes e.g. when they introduced Path class in JDK 7, which is similar to java.


3 Answers

You require only a "simple" map here:

List<List<String>> listOfListValues;
public List<String> getAsFlattenedList() {
    return listOfListValues.stream()
            .map(String::valueOf)
            .collect(toList());
}

flatMap is rather used to transform one Stream to another, which makes sense if you need more entries or less then currently available (or just a newly mapped Stream to filter/map/etc it further down), e.g.:

  • count all the unique strings of all lists:

    listOfListValues.stream()
                    .flatMap(List::stream) // we want to count all, also those from the "inner" list...
                    .distinct()
                    .count()
    
  • truncate entries after a certain size:

    listOfListValues.stream()
            .flatMap(list -> {
                if (list.size() > 3) // in this case we use only some of the entries
                    return Stream.concat(list.subList(0, 2).stream(), Stream.of("..."));
                else
                    return list.stream();
            })
            .collect(Collectors.toList());
    
  • flattening values of a map for several interested keys:

    Map<Key, List<Value>> map = new HashMap<>();
    Stream<Value> valueStream = interestedKeys.stream()
                                              .map(map::get)
                                              .flatMap(List::stream);
    
like image 191
Roland Avatar answered Nov 05 '22 07:11

Roland


No need to use flatmap.

listOfListValues.stream()
        .map(String::valueOf)
        .collect(Collectors.toList());

Explanation: The flatMap function combines a map and a flat operation. This is not needed. Flattening means converting something like [ [1,2,3],[4,5,6,7],[8,9] ] to [ 1,2,3,4,5,6,7,8,9 ] i.e. converting a 2D array to a 1D array.

like image 30
Sid Avatar answered Nov 05 '22 05:11

Sid


You can do it like so,

listOfListValues.stream().map(List::toString).collect(Collectors.toList());
like image 21
Ravindra Ranwala Avatar answered Nov 05 '22 07:11

Ravindra Ranwala