多个IntStreams上的Java 8 forEach

多个IntStreams上的Java 8 forEach,java,lambda,java-8,java-stream,Java,Lambda,Java 8,Java Stream,我有以下代码: 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 -> {

我有以下代码:

    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)到(宽度,高度)的每个节点,在从(x-1,y-1)到(x+1,y+1)的节点上注册观测者,但不是在自身上注册观测者”。

基本上是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
            }
        });
    });
}

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

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);
}
私有静态流getNodes(intx1、intx2、inty1、inty2){
返回IntStream.rangeClosed(x1,x2)
.mapToObj(x->(Stream)IntStream.rangeClosed(y1,y2).mapToObj(y->getNode(x,y)))
.flatMap(节点->节点)
.filter(节点->节点!=null);
}

原则上,可以使用
flatMap
将嵌套循环替换为
。这要求您选择一种元素类型,如果需要,它能够保存与循环变量等效的信息。在您的例子中,它是
x
y
的两个值。如果
节点
类保存了这些信息,那么它将简化代码,因为您可以轻松地迭代节点,而不是
int
值。由于您没有指定
节点
类的功能,下面是一个使用大小为2的
长[]
来保存点的示例:

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);
  });
然后你可以这样使用它:

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);
  });
区域(0,宽度,0,高度).forEach(p1->{
使用者寄存器=getNode(p1[0],p1[1])::registerObserverAtNeighbor;
面积(p1[0]-1,p1[0]+2,p1[1]-1,p1[1]+2)
.filter(p2->(p1[0]!=p2[0]| | p1[1]!=p2[1]))
.map(点->获取节点(点[0],点[1]))
.filter(节点->节点!=null)
.forEach(登记册);
});
如果您有/使用一个专用的点类,或者如果节点类保存点信息(在最好的情况下,它有一个比较方法),那么这可能会更容易

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);
  });