【问题标题】:Java 8 forEach over multiple IntStreams多个 IntStream 上的 Java 8 forEach
【发布时间】:2014-10-18 11:18:47
【问题描述】:

我有以下代码:

    IntStream.range(0, width).forEach(x1 -> {
        IntStream.range(0, height).forEach(y1 -> {
            IntStream.rangeClosed(x1-1, x1+1).forEach(x2 -> {
                IntStream.rangeClosed(y1-1, y1+1).forEach(y2 -> {
                    if ((x1 != x2 || y1 != y2) && getNode(x2, y2) != null){
                        getNode(x1, y1).registerObserverAtNeighbor(getNode(x2, y2));
                    }
                });
            });
        });
    });

有没有办法使用更少的嵌套语句来编写上述内容?它基本上是“对于从 (0,0) 到 (width,height) 的每个节点在 (x-1,y-1) 到 (x+1,y+1) 的节点上注册观察者,但不是在 self”。

【问题讨论】:

    标签: java lambda java-8 java-stream


    【解决方案1】:

    原则上,您可以使用flatMap 将嵌套循环替换为Stream。这要求您选择一种元素类型,该元素类型能够保存与循环变量等效的信息(如果需要)。在您的情况下,它是 xy 的两个值。如果您的 Node 类包含这些信息,它将简化代码,因为您可以轻松地遍历节点而不是 int 值。由于您没有指定 Node 类的功能,因此这里有一个示例,它使用大小为 2 的 long[] 来保存点:

    IntStream.range(0, width).boxed()
      .flatMap(x->IntStream.range(0, height).mapToObj(y->new int[]{ x, y }))
      .forEach(p1 -> {
        Consumer<Node> register=getNode(p1[0], p1[1])::registerObserverAtNeighbor;
        IntStream.rangeClosed(p1[0]-1, p1[0]+1).boxed()
        .flatMap(x->IntStream.rangeClosed(p1[1]-1, p1[1]+1).mapToObj(y->new int[]{ x,y }))
          .filter(p2 -> (p1[0] != p2[0] || p1[1] != p2[1]))
          .map(point -> getNode(point[0], point[1]))
          .filter(node -> node != null)
          .forEach(register);
      });
    

    它仍然通过在可能的情况下将代码移到外部来简化最里面的代码,例如getNode 电话。您还可以通过将在某个区域的点上创建Stream 的重复任务放入方法中来简化代码:

    static Stream<int[]> area(int x0, int x1, int y0, int y1) {
      return IntStream.range(x0, x1).boxed()
      .flatMap(x->IntStream.range(y0, y1).mapToObj(y->new int[]{ x, y }));
    }
    

    那么你可以这样使用它:

    area(0, width, 0, height).forEach(p1 -> {
        Consumer<Node> register=getNode(p1[0], p1[1])::registerObserverAtNeighbor;
        area(p1[0]-1, p1[0]+2, p1[1]-1, p1[1]+2)
          .filter(p2 -> (p1[0] != p2[0] || p1[1] != p2[1]))
          .map(point -> getNode(point[0], point[1]))
          .filter(node -> node != null)
          .forEach(register);
      });
    

    如果您拥有/使用专用点类或节点类保存点信息(并且最好有比较方法),这仍然会更容易。

    【讨论】:

      【解决方案2】:

      您所拥有的基本上是 4 个嵌套循环。这是有道理的,因为您正在迭代矩阵的二维,然后,对于每个节点,您迭代一个由其邻居组成的小矩阵。

      类似的东西。

      0000000
      0---000
      0-X-000
      0---000
      0000000
      

      我猜你可以只为语法使用递归函数,虽然没有任何好处。

      iterateLambdas(0, width, 0, height, 1);
      
      public static void iterateLambdas(
              int start1,
              int end1,
              int start2,
              int end2,
              int depth) {
          IntStream.range(start1, end1).forEach(x1 -> {
              IntStream.range(start2, end2).forEach(y1 -> {
                          if (depth != 0) {
                                iterateLambdas(x1 - 1, x1 + 2, y1 - 1, y1 + 2, depth - 1);
                          } else {
                                // Current node : (start1 + 1), (start2 + 1)
                                // Current neighbour : x1, y1);
                                // Your logic here
                  }
              });
          });
      }
      

      【讨论】:

        【解决方案3】:

        由于您在节点上进行操作,我建议首先创建节点流。请注意,我对节点做了一些假设。

        getNodes(0, width - 1, 0, height - 1).forEach(node -> {
          getNodes(node.getX() - 1, node.getX() + 1, node.getY() - 1, node.getY() + 1)
            .filter(neighbor -> !neighbor.equals(node))
            .forEach(neighbor -> node.registerObserverAtNeighbor(neighbor));
        });
        

        使用您的方法创建流:

        private static Stream<Node> getNodes(int x1, int x2, int y1, int y2) {
          return IntStream.rangeClosed(x1, x2)
            .mapToObj(x -> (Stream<Node>)IntStream.rangeClosed(y1, y2).mapToObj(y -> getNode(x, y)))
            .flatMap(nodes -> nodes)
            .filter(node -> node != null);
        }
        

        【讨论】:

          猜你喜欢
          • 2020-09-02
          • 2015-04-03
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2014-07-03
          • 1970-01-01
          • 2019-03-05
          • 2021-08-05
          相关资源
          最近更新 更多