2016-05-30 34 views
13

Tôi có một số Collection các phần tử của một lớp tùy ý. Tôi muốn lặp qua bộ sưu tập và thực hiện một số hoạt động bằng cách sử dụng phần tử và mỗi phần tử khác của bộ sưu tập từng cái một (không bao gồm chính phần tử đó). Let it be List<Integer> vì đơn giản:Luồng Java 8: xử lý mọi cặp yếu tố có thể có từ danh sách

List<Integer> list = Arrays.asList(1, 2, 3, 4, 5); 

Với for loops nó sẽ là:

for (Integer i : list) { 
    for (Integer j : list) { 
     if (!i.equals(j)) System.out.println(i * 2 + j); //just for example 
    } 
} 

Câu hỏi đặt ra là làm thế nào để làm điều đó với các Stream API?

Đó là những gì tôi đã đến:

list.stream().forEach(i -> 
    list.stream().forEach(j -> { 
     if (!i.equals(j)) System.out.println(i * 2 + j); 
    }) 
); 

Nó không nhìn tốt hơn so với vòng lặp lồng nhau mặc dù. Có cách nào thanh lịch hơn không?

Trả lời

13

Bạn có thể làm điều này bằng cách sử dụng hoạt động flatMap:

list.stream() 
    .flatMap(i -> list.stream().filter(j -> !i.equals(j)).map(j -> i * 2 + j)) 
    .forEach(System.out::println); 

Mã này đang tạo ra một Stream của danh sách đầu vào. Nó phẳng ánh xạ từng phần tử của danh sách với một luồng được tạo bởi cùng một danh sách, trong đó phần tử hiện tại được lọc ra và mỗi phần tử của danh sách mới này là kết quả của hoạt động i * 2 + j.

Tất cả các phần tử sau đó được in trên bảng điều khiển.

6

Bạn có thể tránh so sánh đối tượng bằng cách ánh xạ trước int giá trị trước, ví dụ:

list.stream().mapToInt(Integer::intValue) 
    .flatMap(i -> list.stream().filter(j -> j!=i).mapToInt(j -> i*2 + j)) 
    .forEach(System.out::println); 

Nhưng thực tế, bạn đang thực hiện các hoạt động có điều kiện và kiểm tra bình đẳng cho một thứ bất biến. Khi toàn bộ hoạt động dựa trên danh sách nguồn không thay đổi nội dung của nó ở giữa, bạn chỉ có thể tạo ra các chỉ số danh sách cặp đôi ở nơi đầu tiên:

final int end=list.size(); 
IntStream.range(0, end).flatMap(i -> 
    IntStream.concat(IntStream.range(0, i), IntStream.range(i+1, end)) 
     .map(j -> list.get(i) * 2 + list.get(j))) 
    .forEach(System.out::println); 

Trong trường hợp bạn không muốn tính toán một giá trị số nhưng tạo một đối tượng cho các cặp, nó phức tạp hơn một chút do thực tế là IntStream không có hoạt động flatMapToObj, vì vậy chúng tôi cần kết hợp mapToObjflatMap (trừ khi chúng tôi sử dụng boxed). Vì vậy, xây dựng một hai chiều dài mảng gương mẫu trông giống như:

IntStream.range(0, end).mapToObj(i -> 
    IntStream.concat(IntStream.range(0, i), IntStream.range(i+1, end)) 
     .mapToObj(j -> new int[]{ list.get(i), list.get(j)})) 
     .flatMap(Function.identity()) 
    .forEach(a -> System.out.println(a[0]*2+a[1])); 

Tất nhiên, đối với một danh sách đơn giản như [ 1, 2, 3, 4, 5 ], chúng tôi chỉ có thể sử dụng IntStream.rangeClosed(1, 5) ở nơi đầu tiên, mà không đối phó với một List:

IntStream.rangeClosed(1, 5).flatMap(i -> 
     IntStream.concat(IntStream.range(1, i), IntStream.rangeClosed(i+1, 5)) 
     .map(j -> i*2 + j)) 
    .forEach(System.out::println); 
Các vấn đề liên quan