简体   繁体   English

如何使用流从两个列表或数组乘法中查找元素对

[英]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() 示例之间的区别

你只需要用flatMap()替换你的第一个map() 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 中使用了IntIntPairPrimitiveTuples类,因为它们使将列表作为字符串输出变得更简单。 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解决方案不是线程安全的,如果IntStreamparallel ,则会中断。 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:您可以使用mapreduce方法生成可能组合的二维列表:

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 's Stream#mapMulti and operator on a more declarative way相反,我建议您以更具声明性的方式选择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.

相关问题 如何从两个流中获取相似的元素并收集这样形成的对而不会丢失顺序? - How to get similar elements from two streams and collect the pairs thus formed without losing the order? 如何使用 Java Streams API 在两个相同维度的列表之间进行元素乘法 - How to use Java Streams API to do element wise multiplication between 2 lists of same dimension 从两个元素中的整数数组中找到两对 - finding two pairs from integer array out of two elements 如何使用 Java Streams 比较两个列表并将共同添加到字段 - How to use Java Streams to compare two lists and add common to a field 比较数组中的元素以查找对,但是在找到两个对时无法弄清楚该怎么做 - Comparing elements in my array to find pairs, but can't figure out what to do when it finds two pairs 最好使用一对或两个列表? - Better to use a list of pairs, or two lists? 在两个列表中找到共同的元素 - find common elements in two lists 在Java中的两个列表中找到第一个列表中的唯一元素 - Find unique elements in the first list from two lists in Java 如何使用 Stream 对两个列表进行配对 - How to make Pairs using Stream for two lists Java 8:使用流检查两个列表中的公共元素 - Java 8: check for common elements in two lists using streams
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM