【问题标题】:How can I collect result from nested .forEach in a Java IntStream如何从 Java IntStream 中的嵌套 .forEach 收集结果
【发布时间】:2019-03-05 11:34:38
【问题描述】:

我正在尝试使用 Java Stream 解决这个问题“Two Sum”,而不是使用命令式方法:

Given nums = [2, 7, 11, 15], target = 18,
Because nums[1] + nums[2] = 7 + 11 = 18,
return [1, 2].

这是我的部分工作代码。谁能帮忙解决?我只是不知道如何将它收集起来以作为原始 int 数组返回:

class Solution { 
    public int[] twoSum(int[] input, int target) {
        IntStream.range(0,  input.length)
           .forEach(i -> {
               IntStream.range(0,  input.length)
                   .filter(j -> i != j && input[i] + input[j] == target)
                   .peek(t -> System.out.println(input[t]))
                   .findFirst();
               }
            );
        return null;
    }
}

这是上面的输出(来自 peek):

11
7

【问题讨论】:

  • 你循环和流的方法是不同的。解决方案需要保留一些全局变量,但流通常使用无状态方法转换数据。流可能不是完成这项任务的完美方法。

标签: java arrays loops java-stream


【解决方案1】:

正如我在 cmets 中所说,Streams 并不总是完美的解决方案。但是关于你的任务,看起来你需要一个 Pair 流。不幸的是,Java 没有元组(如 Scala),这就是为什么我建议创建一个简单的 Pair 类。

class Pair {
    int i, j;
    public Pair(int i, int j) {
        this.i = i;
        this.j = j;
    }
}

然后,处理成对流

 IntStream.range(0,  input.length)
                .boxed()
                .flatMap(i -> IntStream.range(0,  input.length).boxed()
                                .map(j -> new Pair(i,j))
                )
                        .filter(p -> p.i != p.j)
                        .filter(p -> input[p.i] + input[p.j] == target)
                        .collect(toList());

【讨论】:

  • 谢谢。我能够让它与 import javafx.util.Pair; 一起工作。结果列表中有“重复的逆对”。只需要过滤掉骗子。
【解决方案2】:

模拟通过索引驱动列表或数组的嵌套for 循环的常用方法是使用IntStreamflatMap

int[] input = {12, 7, 11, 15, 6, 2};
int target = 18;

List<List<Integer>> result = IntStream.range(0, input.length)
    .boxed()
    .flatMap(i -> IntStream.range(i + 1, input.length)
        .filter(j -> input[i] + input[j] == target)
        .mapToObj(j -> Arrays.asList(i, j)))
    .collect(Collectors.toList());

System.out.println(result); // [[0, 4], [1, 2]]

请注意,您不需要 Pair 类来维护从内部流到外部流的状态,因为您可以将所需的过滤器应用于内部流。

此外,内部IntStream 不需要从0 开始,因为您不想在结果中同时包含[i, j][j, i](只需要其中一个)。所以用i + 1开始内部的IntStream就足够了。

【讨论】:

    【解决方案3】:

    问题应该用时间复杂度O(n)来解决:

    Map<Integer, List<Integer>> indexMap = IntStream.range(0, a.length).boxed().collect(Collectors.groupingBy(i -> a[i]));
    
    IntStream.range(0, a.length)
        .boxed()
        .filter(i -> indexMap.containsKey(target - a[i]))
        .flatMap(i -> indexMap.get(target - a[i]).stream().filter(j -> i < j).map(j -> Pair.of(i, j)))
        .forEach(System.out::println);
    

    【讨论】:

      猜你喜欢
      • 2014-12-09
      • 2018-04-14
      • 2014-04-09
      • 1970-01-01
      • 1970-01-01
      • 2018-05-27
      • 2014-10-22
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多