如何在Java8中将列表列表转换为列表?

如果我有一个List<List<Object>>,如何使用Java8的特性将其转换为包含相同迭代顺序的所有对象的List<Object>

560896 次浏览

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

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

您可以使用Eclipse集合中的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集合的贡献者。

flatmap更好,但还有其他方法可以实现相同的目标

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

我只想再解释一个像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.}

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

Stream上的flatMap方法当然可以为您展平这些列表,但它必须为元素创建Stream对象,然后为结果创建Stream

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

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

因为ListIterable,所以这段代码调用#2方法(Java8特性),它继承自Iterable

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

ListIterator按顺序返回项目。

对于Consumer,这段代码将一个方法引用(Java8特性)传递给前Java8方法List.addAll,以顺序添加内部列表元素。

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

正如@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);}

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]

在Python中,这可以使用列表理解来完成。

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]

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

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

扩展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语句。

Listlist=map.values. stream()Collectors.toList()

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

开始,您可以使用Stream#mapMulti

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

如果你需要一个不可变的List,你甚至可以使用toList()作为终端操作

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

下面的代码应该工作:-

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