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


当前回答

我们可以使用flatmap,请参考以下代码:

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

其他回答

将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]

正如@Saravana提到的:

flatmap更好,但也有其他方法可以实现

 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<Object> result = new ArrayList<>();
    listOfLists.forEach(result::addAll);

从java-16开始,您可以使用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();

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

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

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

因为List是Iterable的,所以这段代码调用forEach方法(Java8特性),它继承自Iterable。

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

列表的迭代器按顺序返回项目。

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

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