873

If I have a List<List<Object>>, how can I turn that into a List<Object> that contains all the objects in the same iteration order by using the features of Java 8?

12 Answers 12

1528

You can use flatMap to flatten the internal lists (after converting them to Streams) into a single Stream, and then collect the result into a list:

List<List<Object>> list = ...
List<Object> flat = 
    list.stream()
        .flatMap(List::stream)
        .collect(Collectors.toList());
Sign up to request clarification or add additional context in comments.

5 Comments

@arshajii true, but for some reason I prefer the lambda expression. Perhaps I don't like the look of :: :)
Class::method feels a little weird at first, but it has the benefit that it declares what kind of object you are mapping from. That is something you otherwise lose in streams.
Yet you might want to have a container of a List and in that case you might need to use the lambda (l->l.myList.stream()).
If you need to do explicit casting (array of primitives to List for example) then lambdas may be necessary as well.
Since Java 16, .toList() may be used instead of .collect(Collectors.toList()).
83

The flatMap method on Stream can certainly flatten those lists for you, but it must create Stream objects for element, then a Stream for the result.

You don't need all those Stream objects. Here is the simple, concise code to perform the task.

// listOfLists is a List<List<Object>>.
List<Object> result = new ArrayList<>();
listOfLists.forEach(result::addAll);

Because a List is Iterable, this code calls the forEach method (Java 8 feature), which is inherited from Iterable.

Performs the given action for each element of the Iterable until all elements have been processed or the action throws an exception. Actions are performed in the order of iteration, if that order is specified.

And a List's Iterator returns items in sequential order.

For the Consumer, this code passes in a method reference (Java 8 feature) to the pre-Java 8 method List.addAll to add the inner list elements sequentially.

Appends all of the elements in the specified collection to the end of this list, in the order that they are returned by the specified collection's iterator (optional operation).

1 Comment

Good alternative suggestion that avoids some unnecessary allocations. Would be interesting to see the top heap usage of this when working with some larger collections, to see how they compare to each other.
79

flatmap is better but there are other ways to achieve the same

List<List<Object>> listOfList = ... // fill

List<Object> collect = 
      listOfList.stream()
                .collect(ArrayList::new, List::addAll, List::addAll);

1 Comment

Note that using flatMap you will not close the stream, because with the collect you will need to reopen it again.
69

Method to convert a List<List> to List :

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

See this example:

public class Example {

    public static void main(String[] args) {
        List<List<String>> listOfLists = Collections.singletonList(Arrays.asList("a", "b", "v"));
        List<String> list = listOfLists.stream().flatMap(List::stream).collect(Collectors.toList());

        System.out.println("listOfLists => " + listOfLists);
        System.out.println("list => " + list);
    }

}       

It prints:

listOfLists => [[a, b, c]]
list => [a, b, c]

In Python this can be done using List Comprehension.

list_of_lists = [['Roopa','Roopi','Tabu', 'Soudipta'],[180.0, 1231, 2112, 3112], [130], [158.2], [220.2]]

flatten = [val for sublist in list_of_lists for val in sublist]

print(flatten)
['Roopa', 'Roopi', 'Tabu', 'Soudipta', 180.0, 1231, 2112, 3112, 130, 158.2, 220.2]

6 Comments

This should be marked as the correct answer
Python has a function called reduce, which is essentially foldl.
with actual Java Version you could also shorten it to: listOfLists.stream().flatMap(List::stream).toList();
This is the same as the accepted answer, but just compressed to a single line of code.
@Shorty123 toList() returns an immutable list. So, trying to add a new element to the list will simply lead to UnsupportedOperationException
|
30

Just as @Saravana mentioned:

flatmap is better but there are other ways to achieve the same

 listStream.reduce(new ArrayList<>(), (l1, l2) -> {
        l1.addAll(l2);
        return l1;
 });

To sum up, there are several ways to achieve the same as follows:

private <T> List<T> mergeOne(Stream<List<T>> listStream) {
    return listStream.flatMap(List::stream).collect(toList());
}

private <T> List<T> mergeTwo(Stream<List<T>> listStream) {
    List<T> result = new ArrayList<>();
    listStream.forEach(result::addAll);
    return result;
}

private <T> List<T> mergeThree(Stream<List<T>> listStream) {
    return listStream.reduce(new ArrayList<>(), (l1, l2) -> {
        l1.addAll(l2);
        return l1;
    });
}

private <T> List<T> mergeFour(Stream<List<T>> listStream) {
    return listStream.reduce((l1, l2) -> {
        List<T> l = new ArrayList<>(l1);
        l.addAll(l2);
        return l;
    }).orElse(new ArrayList<>());
}

private <T> List<T> mergeFive(Stream<List<T>> listStream) {
    return listStream.collect(ArrayList::new, List::addAll, List::addAll);
}

Comments

17

I just want to explain one more scenario like List<Documents>, this list contains a few more lists of other documents like List<Excel>, List<Word>, List<PowerPoint>. So the structure is

class A {
  List<Documents> documentList;
}

class Documents {
  List<Excel> excels;
  List<Word> words;
  List<PowerPoint> ppt;
}

Now if you want to iterate Excel only from documents then do something like below..

So the code would be

 List<Documents> documentList = new A().getDocumentList();

 //check documentList as not null

 Optional<Excel> excelOptional = documentList.stream()
                         .map(doc -> doc.getExcel())
                         .flatMap(List::stream).findFirst();
 if(excelOptional.isPresent()){
   Excel exl = optionalExcel.get();
   // now get the value what you want.
 }

I hope this can solve someone's issue while coding...

Comments

14

You can use the flatCollect() pattern from Eclipse Collections.

MutableList<List<Object>> list = Lists.mutable.empty();
MutableList<Object> flat = list.flatCollect(each -> each);

If you can't change list from List:

List<List<Object>> list = new ArrayList<>();
List<Object> flat = ListAdapter.adapt(list).flatCollect(each -> each);

Note: I am a contributor to Eclipse Collections.

2 Comments

why use a third party dependency when the functionality is provided by Java 8?
Eclipse Collections API is on the collection itself, so the code is concise, is one of the main reasons in this case.
6

An expansion on Eran's answer that was the top answer, if you have a bunch of layers of lists, you can keep flatmapping them.

This also comes with a handy way of filtering as you go down the layers if needed as well.

So for example:

List<List<List<List<List<List<Object>>>>>> multiLayeredList = ...

List<Object> objectList = multiLayeredList
    .stream()
    .flatmap(someList1 -> someList1
        .stream()
        .filter(...Optional...))
    .flatmap(someList2 -> someList2
        .stream()
        .filter(...Optional...))
    .flatmap(someList3 -> someList3
        .stream()
        .filter(...Optional...))
    ...
    .collect(Collectors.toList())

This is would be similar in SQL to having SELECT statements within SELECT statements.

2 Comments

Why not use recursion? :)
In my years of experience, recursion in languages like Java is dangerous because it is very easy to eat all of your system's resources by accident. You could do it, but I wouldn't. But maybe an alternative would be to use a loop to build a nested stream, then run the stream. You can't really have an infinite loop in streams from my understanding.
5

Since , you can use Stream#mapMulti

List<Object> result = listOfLists.stream()
                                 .mapMulti((List<Object> list, Consumer<Object> consumer) -> {
                                     list.forEach(consumer::accept);
                                 })
                                 .collect(Collectors.toList());

If you need an immutable List you can even use toList() as terminal operation

List<Object> result = listOfLists.stream()
                                 .mapMulti((List<Object> list, Consumer<Object> consumer) -> {
                                     list.forEach(consumer::accept);
                                 })
                                 .toList();

1 Comment

"Since Java 16" made me feel like a dinosaur
3

We can use flatmap for this, please refer below code :

 List<Integer> i1= Arrays.asList(1, 2, 3, 4);
 List<Integer> i2= Arrays.asList(5, 6, 7, 8);

 List<List<Integer>> ii= Arrays.asList(i1, i2);
 System.out.println("List<List<Integer>>"+ii);
 List<Integer> flat=ii.stream().flatMap(l-> l.stream()).collect(Collectors.toList());
 System.out.println("Flattened to List<Integer>"+flat);

Comments

3

Below code should work:-

    List<Object> result = new ArrayList<>();
    listOfLists.forEach(result::addAll);

Comments

-1

List<List> list = map.values().stream().collect(Collectors.toList());

    List<Employee> employees2 = new ArrayList<>();
    
     list.stream().forEach(
             
             n-> employees2.addAll(n));

4 Comments

Assume that i have List<List<Employee>> in the above code
Please have a read of this help page about how to format code properly. Also, you can edit your answer at any time, rather than posting followup comments.
While this code may solve the question, including an explanation of how and why this solves the problem would really help to improve the quality of your post, and probably result in more up-votes. Remember that you are answering the question for readers in the future, not just the person asking now. Please edit your answer to add explanations and give an indication of what limitations and assumptions apply.
Thanks Yunnosch for the suggestion..I will do it..Happy Coding!

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.