2014-10-18 21 views
5

Tôi có đoạn mã sau:Java 8 foreach trên nhiều IntStreams

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

Có cách nào để viết trên sử dụng ít hơn báo cáo lồng nhau? Về cơ bản nó là "cho mỗi nút từ (0,0) đến (chiều rộng, chiều cao) người quan sát đăng ký tại các nút từ (x-1, y-1) đến (x + 1, y + 1), nhưng không phải ở bản thân".

Trả lời

1

Những gì bạn có về cơ bản là 4 vòng lồng nhau. Nó có ý nghĩa bởi vì bạn đang lặp qua hai chiều của một ma trận, và sau đó, đối với mỗi nút, bạn lặp qua một ma trận nhỏ bao gồm các neighbourg của nó.

Điều gì đó tương tự.

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

Tôi đoán bạn có thể sử dụng hàm đệ quy chỉ cho cú pháp, mặc dù không có lợi ích thực sự.

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

Vì bạn hoạt động trên các nút, tôi đề xuất tạo luồng luồng ở vị trí đầu tiên. Xin lưu ý rằng tôi đang thực hiện một số giả định về các nút.

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

Tạo một dòng sử dụng cách tiếp cận của bạn:

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

Về nguyên tắc, bạn có thể thay thế các vòng lặp lồng nhau với một Stream sử dụng flatMap. Điều này yêu cầu bạn chọn loại phần tử có khả năng giữ thông tin tương đương với các biến vòng lặp, nếu bạn cần. Trong trường hợp của bạn, đó là hai giá trị cho xy. Nó sẽ đơn giản hóa mã nếu lớp Node của bạn nắm giữ những thông tin này vì bạn có thể dễ dàng lặp qua các nút thay vì giá trị int sau đó. Vì bạn không nói rõ khả năng của lớp Node của bạn, đây là một ví dụ trong đó sử dụng một long[] kích thước hai để giữ điểm:

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

Nó vẫn đơn giản hoá mã trong cùng bằng cách di chuyển mã để bên ngoài, nơi có thể, ví dụ các cuộc gọi getNode. Bạn cũng có thể đơn giản hóa mã bằng cách đặt các nhiệm vụ lặp đi lặp lại của việc tạo ra một Stream điểm trên cho một khu vực thành một phương pháp:

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

Sau đó, bạn có thể sử dụng nó như thế nà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); 
    }); 

Nó vẫn có thể là dễ dàng hơn nếu bạn có/sử dụng một lớp điểm chuyên dụng hoặc nếu lớp nút giữ thông tin điểm (và có một phương thức so sánh cho nó, trong trường hợp tốt nhất).