如何在Java 8中将列表列表转换为列表?


Answers:


950

您可以使用flatMap将内部列表(将它们转换为Streams之后)展平为单个Stream,然后将结果收集到列表中:

List<List<Object>> list = ...
List<Object> flat = 
    list.stream()
        .flatMap(List::stream)
        .collect(Collectors.toList());

11
@arshajii是正确的,但是出于某种原因,我更喜欢lambda表达式。也许我不喜欢:::)
Eran

25
Class::method一开始感觉有点奇怪,但是它的好处是它声明了要映射的对象类型。那是您否则会在流中丢失的东西。
ArneHugo

2
但是,您可能需要一个List的容器,在这种情况下,您可能需要使用lambda(l-> l.myList.stream())。
Myoch

2
如果您需要进行显式转换(例如,要列出的基本数组),那么lambda可能也是必要的。
Michael Fulton

52

flatmap 更好,但是还有其他方法可以达到相同目的

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

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

37

上的flatMap方法Stream当然可以为您平整那些列表,但是它必须Stream为element 创建对象,然后Stream为结果创建a 。

您不需要所有这些Stream对象。这是执行任务的简单代码。

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

因为a ListIterable,所以这段代码将调用从继承forEach方法(Java 8功能)Iterable

对中的每个元素执行给定的操作,Iterable直到所有元素都已处理或该操作引发异常。如果指定了顺序,则按照迭代顺序执行操作。

ListIterator回报顺序的项目。

对于Consumer,此代码将方法引用(Java 8功能)传递给Java 8之前的方法,List.addAll以按顺序添加内部列表元素。

按照指定集合的​​迭代器返回的顺序,将指定集合中的所有元素追加到此列表的末尾(可选操作)。


3
一个很好的替代建议,可以避免一些不必要的分配。在处理一些较大的集合时,看看它的最大堆用法,以及如何将它们相互比较会很有趣。
Per Lundberg

12

您可以使用Eclipse Collections中flatCollect()模式。

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

如果您无法从更改列表List

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

注意:我是Eclipse Collections的撰稿人。


21
Java 8提供功能时,为什么要使用第三方依赖项?
saw303

2
Eclipse Collections API位于集合本身上,因此代码简洁明了,是这种情况下的主要原因之一。
Nikhil Nanivadekar '17

11

就像@Saravana提到的那样:

平面图更好,但还有其他方法可以实现相同的效果

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

总结起来,有几种方法可以达到以下目的:

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);
}

11

我只是想说明一个更喜欢的场景List<Documents>,这个列表中包含像其他文件的几个表List<Excel>List<Word>List<PowerPoint>。所以结构是

class A {
  List<Documents> documentList;
}

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

现在,如果您只想从文档中迭代Excel,请执行以下操作。

所以代码是

 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.
 }

我希望这可以解决编码时某人的问题...


1

我们可以为此使用平面地图,请参考以下代码:

 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);

1

对Eran的答案的扩展是最重要的答案,如果您有一堆列表,则可以继续对它们进行映射。

如果需要的话,这还提供了一种便捷的过滤方式,可以在您进入各层时进行过滤。

因此,例如:

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())

在SQL中,这类似于在SELECT语句中包含SELECT语句。


1

方法将转换List<List>List

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

请参阅以下示例:

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);
    }

}       

它打印:

listOfLists => [[a, b, c]]
list => [a, b, c]
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.