2015-07-28 38 views
20

Tôi đang cố gắng tìm intersection trong hai danh sách dựa trên một số điều kiện và thực hiện một số bước. không thể tìm thấy một cách để làm điều đó (trong giai đoạn học tập) :)Java 8 Lambda - Giao điểm của hai danh sách

Double totalAmount = 0.00d; 
Double discount = 0.00d; 


List<OrderLineEntry> orderLineEntryList = orderEntry.getOrderReleases().stream().flatMap(orderReleaseEntry -> 
    orderReleaseEntry.getOrderLines().stream()).filter(orderLineEntry -> orderLineEntry.getStatus().equals("PP") 
     || orderLineEntry.getStatus().equals("PD")).collect(Collectors.toList()); 

for (OrderLineEntry orderLineEntry : orderLineEntryList) { 
    for (SplitLineEntry splitLineEntry : splitReleaseEntry.getLineEntries()) { 
     if (splitLineEntry.getOrderLineId().equals(orderLineEntry.getId()) && splitLineEntry.getStatusCode() != 
      "PX") { 
      totalAmount += orderLineEntry.getFinalAmount(); 
      couponDiscount += orderLineEntry.getCouponDiscount() == null ? 0.00d : orderLineEntry.getCouponDiscount(); 
     } 
    } 
} 

Như bạn thấy, logic rất đơn giản

Nhận Tất cả các mục từ theo thứ tự dựa trên một số bộ lọc list và giao nhau với list khác và làm một số thứ.

+3

Cách hiệu quả nhất để tìm giao lộ là sử dụng Tập hợp hoặc Bản đồ. Tôi đề nghị bạn xây dựng một tập hợp bằng cách thu thập một nhóm thích hợp. –

+0

@PeterLawrey, Bạn có thể giúp tôi đạt được điều tương tự với Lambda không. Tôi đang tạo danh sách chỉ để tìm giao lộ. Mã hóa Java điển hình, tôi sẽ sử dụng 'Bản đồ' :) – Reddy

Trả lời

67

Phương pháp đơn giản nhất là thế này:

List<T> intersect = list1.stream() 
         .filter(list2::contains) 
         .collect(Collectors.toList()); 
+4

Tôi đã thấy ví dụ này. Làm thế nào để tôi sử dụng điều này cho trường hợp sử dụng của tôi. Vì 'list1' và list2 là các kiểu khác nhau và tôi cần so sánh chúng với giả định' list1.id == list2.fk_id' – Reddy

+6

Như một sự tối ưu hóa, tôi sẽ chuyển list2 thành HashSet trước. –

+1

chứa là O (n), vì vậy đây là một O (n^2) thiết lập giao lộ hoạt động – fairidox

10

Tôi cần phải so sánh chúng trên giả định list1.id == list2.fk_id

đầu tiên xây dựng một bộ các fk_id;

Set<Integer> orderLineEntrSet = orderEntry.getOrderReleases().stream() 
    .flatMap(orderReleaseEntry -> 
orderReleaseEntry.getOrderLines().stream()) 
    .filter(orderLineEntry -> { 
      String s = orderLineEntry.getStatus(); 
      return "PP".equals(s) || "PD".equals(s); 
    }) 
    .map(e -> e.getId()) 
    .collect(Collectors.toSet()); 

double[] totalAmount = { 0.0 }; 
double[] couponDiscount = { 0.0 }; 
orderLineEntryList.stream() 
    .flatMap(sre -> sre.getLineEntries().stream()) 
    .filter(ole -> orderLineEntrySet.contains(ole.getOrderLineId()) 
    .filter(ole -> !"PX".equals(ole.getStatusCode())) 
    .forEach(ole -> { 
      totalAmount[0] += ole.getFinalAmount(); 
      if (ole.getCouponDiscount() != null) 
       couponDiscount[0] += ole.getCouponDiscount(); 
     }); 

Bạn có thể tránh sử dụng tham chiếu đến đối tượng mảng bằng cách sử dụng hàm reduce. ví dụ. xem Collectors.averagingDouble được triển khai như thế nào. Nhưng tôi thấy điều này phức tạp hơn.

Lưu ý: đây là O (N) bằng cách sử dụng một tập hợp các id hơn là sử dụng một danh sách các id khớp đó sẽ là O (N^2)

+2

Không chắc chắn về O (N). Vì bạn cần phải làm một 'chứa' trong danh sách thứ hai, tôi nghĩ rằng đây vẫn là O (N^2). – HakunaM

+2

@HakunaM Set.contains bằng cách sử dụng một bộ băm là O (1) phân bổ (và O (log N) cho một bộ cây) Collectors.toSet() trả về một bộ băm. –

-3

Danh sách giao nhau = list1.stream() lọc (. set1 :: contains) .collect (Collectors.toList());

Điều này sẽ làm việc trong đó T là Chuỗi, Số nguyên, Float v.v. trong đó bằng, hashcode khá đơn giản. Nhưng nếu T là đối tượng tùy chỉnh, chúng tôi cần triển khai HashCode & bằng

+0

câu trả lời này, được thêm vào một năm sau, không khác với câu trả lời được bình chọn hàng đầu khác ngoài câu trả lời nhiều hơn và ít được định dạng hơn .. – harschware

Các vấn đề liên quan