我有以下代码:
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)的节点处注册观察者,基本上是#34;但不是在自我"。
答案 0 :(得分: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
}
});
});
}
答案 1 :(得分:1)
原则上,您可以使用Stream
将嵌套循环替换为flatMap
。这要求您选择一种能够保存等效于循环变量的信息的元素类型(如果需要)。在您的情况下,它是x
和y
的两个值。如果您的Node
类包含这些信息,它会简化代码,因为您可以轻松地迭代节点而不是int
值。由于您未指定Node
类的功能,因此以下示例使用大小为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 :(得分:0)
由于您在节点上运行,我建议首先创建节点流。请注意,我对节点做了一些假设。
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);
}