[英]How to use streams to find pairs of elements from two lists or array multiplication
I have two lists of numbers and I'd like to find all possible pairs of numbers.我有两个数字列表,我想找到所有可能的数字对。 For example, given the lists
[1, 2, 3]
and [3, 4]
the result should be:例如,给定列表
[1, 2, 3]
和[3, 4]
结果应该是:
[(1, 3), (1, 4), (2, 3), (2, 4), (3, 3), (3, 4)]
I know I can do this using a for loop but is there any more concise way to do it using Java 8 streams ?我知道我可以使用for 循环来做到这一点,但是有没有更简洁的方法可以使用Java 8 流来做到这一点?
I tried the following, but I'm missing something as I'm getting List<Stream<int[]>>
instead of List<int[]>
.我尝试了以下操作,但是我错过了一些东西,因为我得到的是
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] + "}");
});
}
Use flatMap() method instead of map() , it will combine the streams into one.使用flatMap()方法而不是map() ,它将流合并为一个。 Refer : Difference Between map() and flatMap() and flatMap() example
请参阅: map() 和 flatMap()和flatMap() 示例之间的区别
Here is a solution using IntStream
with two int
arrays as the source instead of List<Integer>
.这是一个使用
IntStream
和两个int
数组作为源而不是List<Integer>
的解决方案。 I wanted to see if it was possible to solve this problem without boxing every int
as an 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]
Unfortunately, I couldn't use flatMap
on IntStream
as it returns an IntStream
.不幸的是,我不能在
IntStream
上使用flatMap
因为它返回一个IntStream
。 There is no flatMapToObj
currently on IntStream
, which is what would be needed here.没有
flatMapToObj
目前IntStream
,这是此处将需要的东西。 So I used forEach
instead.所以我用
forEach
代替。
The IntIntPair
and PrimitiveTuples
classes I used from Eclipse Collections , as they made it simpler to just output the list as a string.我在Eclipse Collections 中使用了
IntIntPair
和PrimitiveTuples
类,因为它们使将列表作为字符串输出变得更简单。 You could use int[]
as you have in your solution.您可以在解决方案中使用
int[]
。 The code would look as follows.代码如下所示。
List<int[]> list = new ArrayList<>();
IntStream.of(one).forEach(i ->
IntStream.of(two).mapToObj(j -> new int[]{i, j}).forEach(list::add));
In the 8.1 release of Eclipse Collections (to be released mid-March), there is now a flatCollect
method on all primitive containers in the library which can be used to solve this problem.在 Eclipse Collections 的 8.1 版本(将于 3 月中旬发布)中,现在库中所有原始容器上都有一个
flatCollect
方法,可以用来解决这个问题。 This essentially does what a flatMapToObj
method on IntStream
should do.这本质上做了什么
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]
Update:更新:
As pointed out in the comments by Boris the Spider, the forEach
solution would not be thread-safe and would break if the IntStream
was parallel
.正如 Boris the Spider 的评论中指出的那样,
forEach
解决方案不是线程安全的,如果IntStream
是parallel
,则会中断。 The following solution should work in serial or parallel.以下解决方案应串行或并行工作。 I'm glad this was pointed out, because I hadn't thought to do a
mapToObj
on the IntStream
and then followed by a flatMap
.我很高兴有人指出这一点,因为我没想过在
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);
Note: I am a committer for Eclipse Collections .注意:我是Eclipse Collections的提交者。
In this particular case using flatMap
you can even bypass an array creation and make your code simpler like this:在这种使用
flatMap
特殊情况下,您甚至可以绕过数组创建并使您的代码更简单,如下所示:
list1.stream()
.flatMap(i -> list2.stream().map(j -> "{" + i+ "," + j + "}"))
.forEach(System.out::println);
//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);
You can generate a 2d list of possible combinations using map
and reduce
methods:您可以使用
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]]
See also: Generate all combinations from multiple lists另请参阅:从多个列表生成所有组合
Of course, you can create a Stream
everytime in the Stream#flatMap
but in terms of performance, it's very poor.当然,你可以在
Stream#flatMap
每次都创建一个Stream
,但是在性能方面,它很差。
Instead, I'd advise you to choose for java-16 's Stream#mapMulti
and operator on a more declarative way相反,我建议您以更具声明性的方式选择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();
Which produces the same result, without the overhead of Stream
creation产生相同的结果,没有
Stream
创建的开销
{1,3}
{1,4}
{2,3}
{2,4}
{3,3}
{3,4}
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.