Java 8 forEach over multiple IntStreams
我有以下代码:
1 2 3 4 5 6 7 8 9 10 11 | 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)的节点观察者,但不针对自身"。
原则上,您可以使用
1 2 3 4 5 6 7 8 9 10 11 | 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); }); |
在可能的情况下,例如,通过将代码移到外部,它仍然简化了最内部的代码。
1 2 3 4 | 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 })); } |
然后您可以像这样使用它:
1 2 3 4 5 6 7 8 | 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); }); |
如果您拥有/使用专用的点类,或者如果节点类拥有点信息(并且在最佳情况下具有比较方法),这可能会更加容易。
您拥有的基本上是4个嵌套循环。这是有道理的,因为您要遍历矩阵的两个维,然后,对于每个节点,遍历一个由其邻居组成的小矩阵。
类似这样的东西。
1 2 3 4 5 | 0000000 0---000 0-X-000 0---000 0000000 |
我想您可以仅将递归函数用于语法,尽管实际上没有任何好处。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 | 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 } }); }); } |
由于您在节点上进行操作,因此我建议首先创建节点流。请注意,我对节点进行了一些假设。
1 2 3 4 5 | 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)); }); |
使用您的方法创建流:
1 2 3 4 5 6 | 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); } |