Flattening a List of List to a List with Java 8 stream API
Asked Answered
F

5

6

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.

Fawnfawna answered 28/11, 2018 at 9:3 Comment(0)
T
12

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);
    
Treharne answered 28/11, 2018 at 9:4 Comment(0)
J
4

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.

Jacalynjacamar answered 28/11, 2018 at 9:6 Comment(0)
O
2

You can do it like so,

listOfListValues.stream().map(List::toString).collect(Collectors.toList());
Obstruent answered 28/11, 2018 at 9:15 Comment(1)
If I try to print your list like this: System.out.println(listOfLists.stream().map(List::toString).collect(Collectors.toList())); I get the following output: [[1, 2, 3, 4, 5], [10, 20, 30, 40], [100, 200, 300, 400]]Wideranging
W
0

You can use a flatMap here:

  List<List<Integer>> listOfLists = new ArrayList<>();
    listOfLists.add(Arrays.asList(1,2,3,4,5));
    listOfLists.add(Arrays.asList(10,20,30,40));
    listOfLists.add(Arrays.asList(100,200,300,400));

    System.out.println(listOfLists);

    List<Integer> collect = listOfLists.stream().flatMap(Collection::stream).collect(Collectors.toList());
    System.out.println(collect);

And the output is: [[1, 2, 3, 4, 5], [10, 20, 30, 40], [100, 200, 300, 400]]

[1, 2, 3, 4, 5, 10, 20, 30, 40, 100, 200, 300, 400]

Wideranging answered 28/11, 2018 at 9:56 Comment(0)
A
0

I use reduce operation on stream for this:

var b = List.of(5, 6, 7, 8);
var a = List.of(1, 2, 3, 4);
var c = List.of(a, b);
var res = c.stream().reduce(new ArrayList<>(), (r, l) -> {
  r.addAll(l);
  return r;
});
Animadversion answered 19/2 at 15:19 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.