有什么方法可以仅使用 `map` 而不是使用 `flatMap` 将二维列表转换为一维列表?
Is there any way to convert a 2D List to 1D List using only `map` not using `flatMap`?
我是 Java 初学者,我刚刚了解 map
和 flatMap
。
当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
。我总是追求简单和基本的东西。
如果在 collect
期间执行平面映射,则可以删除 flatMap
:
List<Integer> lst1 = list_2d
.stream()
.collect(Collectors.flatMapping (List::stream, Collectors.toList()));
但是,我没有看到使用 Collectors.flatMapping
而不是 flatMap
的优势。
回答这个问题,还有其他方法,但我不会推荐任何我能想到的。例如你可以使用 reduction:
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() 不能互换吗?
Just because, if map can replaced all of flatMap, there are no reason
to memorize flatMap. I always pursue simple and basic thing.
你已经掌握了最简单和最基本的东西。此外,为了充分发挥流的潜力,您需要不时使用许多方法调用。在使用流多年之后,我仍然发现自己有时会在 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()
至少足够好,以便在我们需要时能够查找它们。
可能这不是您要查找的内容,但如果目标是将所有子列表添加到一个结果列表中,就 简单和基本而言,使用 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);
由于已经有几个答案提供了不同的实现方式,我将尝试展示 map
和 flatMap
之间的区别。
map
操作用于将流中的每个元素准确地更改为另一个元素。在您的示例中,可能的用例可能是在列表上进行一些聚合(例如,对所有元素求和),产生一个 List<Integer>
包含各个列表的所有总和。或者您可以更改数据结构,也许更改为一个集合,生成 List<Set<Integer>>
。结果列表中的元素数将始终为 2,因为原始列表有 2 个元素。
另一方面,flatMap
操作用于将一个元素转换为零个或多个元素。考虑一个由许多人组成的 class 家庭。如果您从某个地方获得家庭列表,但您只关心个人,则可以 flatMap
家庭列表到人类列表。
flatMap
和其他答案中给出的实现之间的区别在于操作的类型:flatMap
是一个中间操作,意味着结果是Stream
。 collect
和 reduce
是终端操作,这意味着结果有所不同(在您的示例中:List<Integer>
。如果您想执行更多流操作(例如 filter
或另一个 map
) 您将必须创建另一个 Stream
结果列表。
为了说明这一点,请考虑在您的问题中给出列表,因此您希望列表中的所有偶数。我正在使用 答案中的 collect
解决方案。如您所见,使用 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]
}
您可以遍历此 2d-list 并将其中的元素(整数)添加到另一个 1d-list:
-
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]
-
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]
我是 Java 初学者,我刚刚了解 map
和 flatMap
。
当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
。我总是追求简单和基本的东西。
如果在 collect
期间执行平面映射,则可以删除 flatMap
:
List<Integer> lst1 = list_2d
.stream()
.collect(Collectors.flatMapping (List::stream, Collectors.toList()));
但是,我没有看到使用 Collectors.flatMapping
而不是 flatMap
的优势。
回答这个问题,还有其他方法,但我不会推荐任何我能想到的。例如你可以使用 reduction:
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() 不能互换吗?
Just because, if map can replaced all of flatMap, there are no reason to memorize flatMap. I always pursue simple and basic thing.
你已经掌握了最简单和最基本的东西。此外,为了充分发挥流的潜力,您需要不时使用许多方法调用。在使用流多年之后,我仍然发现自己有时会在 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()
至少足够好,以便在我们需要时能够查找它们。
可能这不是您要查找的内容,但如果目标是将所有子列表添加到一个结果列表中,就 简单和基本而言,使用 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);
由于已经有几个答案提供了不同的实现方式,我将尝试展示 map
和 flatMap
之间的区别。
map
操作用于将流中的每个元素准确地更改为另一个元素。在您的示例中,可能的用例可能是在列表上进行一些聚合(例如,对所有元素求和),产生一个 List<Integer>
包含各个列表的所有总和。或者您可以更改数据结构,也许更改为一个集合,生成 List<Set<Integer>>
。结果列表中的元素数将始终为 2,因为原始列表有 2 个元素。
另一方面,flatMap
操作用于将一个元素转换为零个或多个元素。考虑一个由许多人组成的 class 家庭。如果您从某个地方获得家庭列表,但您只关心个人,则可以 flatMap
家庭列表到人类列表。
flatMap
和其他答案中给出的实现之间的区别在于操作的类型:flatMap
是一个中间操作,意味着结果是Stream
。 collect
和 reduce
是终端操作,这意味着结果有所不同(在您的示例中:List<Integer>
。如果您想执行更多流操作(例如 filter
或另一个 map
) 您将必须创建另一个 Stream
结果列表。
为了说明这一点,请考虑在您的问题中给出列表,因此您希望列表中的所有偶数。我正在使用 collect
解决方案。如您所见,使用 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]
}
您可以遍历此 2d-list 并将其中的元素(整数)添加到另一个 1d-list:
-
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]
-
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]