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

时间:2017-02-14 07:19:00

标签: java java-8 java-stream matrix-multiplication

我有两个数字列表,我想找到所有可能的数字对。例如,给定列表[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]+ "}");
    });
}

7 个答案:

答案 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中使用的IntIntPairEclipse 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解决方案不是线程安全的,如果IntStreamparallel,它将会中断。以下解决方案应该以串行或并行方式工作。我很高兴有人指出这一点,因为我没有考虑在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)

您可以使用 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]]

另见:Generate all combinations from multiple lists

答案 6 :(得分:0)

当然,您可以每次在 Stream 中创建一个 Stream#flatMap,但在性能方面,它很差。

相反,我建议您以更具声明性的方式选择 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}