5

我是一名 Java 初学者,我刚刚了解了mapflatMap.

当 2d List 应该转换为 1d List 时,它的实现如下所示。

List<List<Integer>> list_2d = List.of(List.of(1, 2), List.of(3, 4));

List<Integer> lst1 = list_2d
    .stream()
    .flatMap(arr -> arr.stream())
    .collect(Collectors.toList());
printAll(lst1); // [1, 2, 3, 4]

但是,我认为它看起来可以不使用flatMap.

有什么方法可以使代码具有相同的逻辑,只是使用map,而不是使用flatMap

只是问,因为如果map可以替换所有flatMap,没有理由去死记硬背flatMap。我总是追求简单和基本的东西。

4

5 回答 5

9

要回答所提出的问题,还有其他方法,但我不会推荐任何我能想到的方法。例如,您可以使用归约:

    List<List<Integer>> list2d = List.of(List.of(1, 2), List.of(3, 4));

    List<Integer> lst1 = list2d
        .stream()
        .reduce((l1, l2) -> {
            ArrayList<Integer> concatenated = new ArrayList<>(l1);
            concatenated.addAll(l2);
            return concatenated;
        })
        .orElse(List.of()); // or else empty list
    
    System.out.println(lst1);

输出与您的相同:

[1、2、3、4]

但是你的代码比我的更容易理解。我建议你坚持下去。

map() 和 flatMap() 不能互换吗?

正因为,如果map可以代替所有的flatMap,那么就没有理由去记住flatMap了。我总是追求简单和基本的东西。

你已经得到了最简单和最基本的东西。此外,为了充分发挥流的潜力,您需要不时使用许多方法调用。在使用流多年后,我仍然发现自己有时会在 Javadoc 中查找它们。我不得不查找reduce()这个答案的详细信息。不要期望一切都在你的脑海中。不过,我确实知道flatMap(),因为它通常很实用。

编辑:仅出于学术兴趣:通常您不能替换flatMap()map(). 或者你会map()从一开始就使用。但反过来:你总是可以map()flatMap(). 你只是不想。例如,如果我们有:

    List<String> strings = List.of("short", "somewhat longer");
    List<Integer> lengths = strings.stream()
            .map(String::length)
            .collect(Collectors.toList());
    System.out.println(lengths);

[5, 15]

如果出于某种奇怪的原因,我们只能记住flatMap(),而不是map(),我们可以这样做:

    List<Integer> lengths = strings.stream()
            .flatMap(s -> Stream.of(s.length()))
            .collect(Collectors.toList());

我认为很明显,它给我们带来的只是不必要的复杂性。最好记住这两者,map()至少flatMap()要足够好,以便在我们需要它们时能够查找它们。

于 2020-12-20T10:32:51.690 回答
6

flatMap如果您在以下期间执行平面映射,则可以删除collect

List<Integer> lst1 = list_2d
    .stream()
    .collect(Collectors.flatMapping (List::stream, Collectors.toList()));

但是,我没有看到使用Collectors.flatMapping而不是flatMap.

于 2020-12-20T10:19:27.817 回答
5

可能这不是您要寻找的,但如果目标是将所有子列表添加到一个结果列表中,就简单和基本而言,使用 for each 也可能是一种选择:

List<List<Integer>> list_2d = List.of(List.of(1, 2), List.of(3, 4));
List<Integer> result = new ArrayList<>();
list_2d.forEach(list -> result.addAll(list));
System.out.println(result);
于 2020-12-20T10:49:37.873 回答
2

map由于已经有几个答案提供了不同的实现,我将尝试展示和之间的区别flatMap

map操作用于将流的每个元素更改为恰好另一个元素。在您的示例中,可能的用例可能是对列表进行一些聚合(例如,对所有元素求和),产生List<Integer>包含各个列表的所有总和的 a。或者你可以改变数据结构,也许是一个集合,产生一个List<Set<Integer>>. 结果列表中的元素数将始终为 2,因为原始列表有 2 个元素。

flatMap另一方面,该操作用于将一个元素转换为零个或多个元素。考虑一个由许多人类组成的类家庭。如果您从某个地方获得家庭列表,但您只关心个人,则可以flatMap将家庭列表添加到人类列表。

flatMap与其他答案中给出的实现之间的区别在于操作的类型:flatMap是中间操作,意味着结果是 a Streamcollect并且reduce是终端操作,这意味着结果是不同的(在您的示例中: a List<Integer>。如果您想执行更多的流操作(例如filter或另一个map),则必须创建另一个Stream结果列表。

为了说明这一点,请考虑在您的问题中给出列表,因此您希望从列表中获得所有偶数。我正在使用这个答案中的collect解决方案。如您所见,使用可以节省不必要的 List 创建以及一些代码行。flatMap

public static void usingFlatMap() {
    List<List<Integer>> originalList = Arrays.asList(Arrays.asList(1, 2), Arrays.asList(3, 4));

    List<Integer> result = originalList
            .stream()
            .flatMap(list -> list.stream())
            .filter(number -> number % 2 == 0)
            .collect(Collectors.toList());

    System.out.println(result); // [2, 4]
}

public static void usingCollect() {
    List<List<Integer>> originalList = Arrays.asList(Arrays.asList(1, 2), Arrays.asList(3, 4));

    List<Integer> intermediateList = originalList
            .stream()
            .collect(Collectors.flatMapping(List::stream, Collectors.toList()));
    List<Integer> result = intermediateList
            .stream()
            .filter(number -> number % 2 == 0)
            .collect(Collectors.toList());

    System.out.println(result); // [2, 4]
}
于 2020-12-20T12:19:35.203 回答
0

您可以遍历此2d-list并将其中的元素(整数)添加到另一个1d-list


  1. List<List<Integer>> list_2d = List.of(List.of(1, 2), List.of(3, 4));
    
    List<Integer> list_1d = new ArrayList<>();
    
    IntStream.range(0, list_2d.size()).forEach(i ->
            IntStream.range(0, list_2d.get(i).size()).forEach(j ->
                    list_1d.add(list_2d.get(i).get(j))));
    
    System.out.println(list_1d); // [1, 2, 3, 4]
    

  1. List<List<Integer>> list_2d = List.of(List.of(1, 2), List.of(3, 4));
    
    List<Integer> list_1d = new ArrayList<>();
    
    list_2d.forEach(list ->
            list.forEach(element ->
                    list_1d.add(element)));
    
    System.out.println(list_1d); // [1, 2, 3, 4]
    
于 2020-12-22T18:13:18.960 回答