我有两个数字列表,我想找到所有可能的数字对。例如,给定列表[1,2,3]和[3,4],结果应该是[(1,3),(1,4),(2,3),(2,4),(3) ,3),(3,4)]。
我知道我可以使用for
循环来实现这一点但是有没有更简洁的方法来使用Java 8流?
我尝试了以下操作,但由于我收到了List<Stream<int[]>>
而不是List<int[]>
,因此我遗漏了一些内容。
public static void main(String[] args) {
List<Integer> list1 = Arrays.asList(1, 2, 3);
List<Integer> list2 = Arrays.asList(3, 4);
List<int[]> pairs = list1.stream().map(i -> list2.stream().map(j -> new int[] { i, j }))
.collect(Collectors.toList());
pairs.forEach(i -> {
System.out.println("{" + i[0]+ "," + i[1]+ "}");
});
}
答案 0 :(得分:15)
使用 flatMap()方法代替 map(),它会将流合并为一个。 请参阅:Difference Between map() and flatMap()和flatMap() example
答案 1 :(得分:14)
您只需将第一个map()
替换为flatMap()
。
答案 2 :(得分:14)
以下是使用IntStream
并使用两个int
数组作为源代替List<Integer>
的解决方案。我想看看是否有可能解决这个问题,而不是将int
作为Integer
进行装箱。
int[] one = new int[]{1, 2, 3};
int[] two = new int[]{3, 4};
List<IntIntPair> list = new ArrayList<>();
IntStream.of(one).forEach(i ->
IntStream.of(two).mapToObj(j -> PrimitiveTuples.pair(i, j)).forEach(list::add));
System.out.println(list);
// [1:3, 1:4, 2:3, 2:4, 3:3, 3:4]
很遗憾,我无法在flatMap
上使用IntStream
,因为它会返回IntStream
。当前flatMapToObj
上没有IntStream
,这是此处需要的。所以我改为使用了forEach
。
我在PrimitiveTuples
中使用的IntIntPair
和Eclipse Collections类,因为它们只是将列表作为字符串输出更简单。您可以在解决方案中使用int[]
。代码如下所示。
List<int[]> list = new ArrayList<>();
IntStream.of(one).forEach(i ->
IntStream.of(two).mapToObj(j -> new int[]{i, j}).forEach(list::add));
在Eclipse Collections的8.1版本中(将于3月中旬发布),现在库中的所有原始容器都有一个flatCollect
方法,可用于解决此问题。这基本上与flatMapToObj
上的IntStream
方法应该做的事情有关。
IntList a = IntLists.mutable.with(1, 2, 3);
IntList b = IntLists.mutable.with(3, 4);
List<IntIntPair> result =
a.flatCollect(
i -> b.collect(j -> PrimitiveTuples.pair(i, j)),
Lists.mutable.empty());
System.out.println(result);
// [1:3, 1:4, 2:3, 2:4, 3:3, 3:4]
更新:
正如Boris the Spider的评论所指出的那样,forEach
解决方案不是线程安全的,如果IntStream
是parallel
,它将会中断。以下解决方案应该以串行或并行方式工作。我很高兴有人指出这一点,因为我没有考虑在mapToObj
上进行IntStream
,然后是flatMap
。
int[] one = new int[]{1, 2, 3};
int[] two = new int[]{3, 4};
List<int[]> list = IntStream.of(one).parallel()
.mapToObj(i -> IntStream.of(two).mapToObj(j -> new int[]{i, j}))
.flatMap(e -> e)
.collect(Collectors.toList());
list.stream().map(e -> "{" + e[0] + "," + e[1] + "}").forEach(System.out::println);
注意:我是Eclipse Collections的提交者。
答案 3 :(得分:0)
在使用flatMap
的特定情况下,您甚至可以绕过数组创建并使代码更简单:
list1.stream()
.flatMap(i -> list2.stream().map(j -> "{" + i+ "," + j + "}"))
.forEach(System.out::println);
答案 4 :(得分:0)
//return pair of numbers
List<List<Integer>> pairs=numbers.stream()
.flatMap(i -> numbers2.stream()
.map(j -> Arrays.asList(i,j)))
.collect(Collectors.toList());
pairs.stream().forEach(System.out::println);
答案 5 :(得分:0)
您可以使用 map
和 reduce
方法生成可能组合的二维列表:
List<Integer> list1 = Arrays.asList(1, 2, 3);
List<Integer> list2 = Arrays.asList(3, 4);
List<List<Integer>> combinations = Stream.of(list1, list2)
// represent each list element as a singleton list
.map(list -> list.stream().map(Collections::singletonList)
// Stream<List<List<Integer>>>
.collect(Collectors.toList()))
// intermediate output
//[[1], [2], [3]]
//[[3], [4]]
.peek(System.out::println)
// summation of pairs of inner lists
.reduce((listA, listB) -> listA.stream()
// combinations of inner lists
.flatMap(inner1 -> listB.stream()
// merge two inner lists into one
.map(inner2 -> Stream.of(inner1, inner2)
.flatMap(List::stream)
.collect(Collectors.toList())))
// list of combinations
.collect(Collectors.toList()))
// otherwise an empty list
.orElse(Collections.emptyList());
// output
System.out.println(combinations);
// [[1, 3], [1, 4], [2, 3], [2, 4], [3, 3], [3, 4]]
答案 6 :(得分:0)
当然,您可以每次在 Stream
中创建一个 Stream#flatMap
,但在性能方面,它很差。
相反,我建议您以更具声明性的方式选择 java-16 的 Stream#mapMulti
和运算符
List<int[]> pairs = list1.stream()
.mapMulti((Integer left, Consumer<int[]> consumer) ->
list2.forEach(right -> consumer.accept(new int[]{left, right})))
.toList();
产生相同的结果,没有 Stream
创建的开销
{1,3}
{1,4}
{2,3}
{2,4}
{3,3}
{3,4}