2015-07-28 17 views
20

Próbuję znaleźć intersection dwóch list na podstawie pewnych warunków i wykonując kilka kroków. Nie udało się znaleźć sposób, aby to zrobić (w fazie uczenia się) :)Java 8 Lambda - przecięcie dwóch list

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

Jak widać, logika jest prosta

uzyskać wszystkie elementy z rzędu na podstawie jakiegoś filtra list i przecinają się z innym list i rób kilka rzeczy.

+3

Najbardziej skutecznym sposobem znalezienia skrzyżowania jest użycie zestawu lub mapy. Proponuję skonstruować zestaw, zbierając odpowiednie groupingBy. –

+0

@PeterLawrey, Czy możesz mi pomóc osiągnąć to samo z Lambdą. Tworzę listę tylko po to, aby znaleźć skrzyżowanie. Typowe kodowanie Java, użyłbym 'Map' :) – Reddy

Odpowiedz

67

Najprostsze podejście jest takie:

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

Widziałem ten przykład. Jak mogę tego użyć w moim przypadku użycia. Ponieważ 'list1' i list2 są różnych typów i muszę je porównać przy założeniu' list1.id == list2.fk_id' – Reddy

+6

Jako optymalizację, najpierw zamieniłbym list2 na HashSet. –

+1

zawiera O (n), więc jest to operacja O (n^2) ustawiania przecięć – fairidox

10

muszę porównać je zakładać list1.id == list2.fk_id

Pierwszy zbudować zestaw na 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(); 
     }); 

Można uniknąć odniesienia do obiektu tablicy za pomocą funkcji zmniejszania. na przykład zobacz, jak zaimplementowano narzędzie Collectors.averagingDouble. Ale uważam to za bardziej skomplikowane.

uwaga: O (N), przy użyciu zestawu identyfikatorów, a nie za pomocą listy dopasowania identyfikatorów, które byłyby O (N^2)

+2

Not sure about the O (N). Ponieważ musisz zrobić "zawiera" na drugiej liście, myślę, że to nadal jest O (N^2). – HakunaM

+2

@HakunaM Set.contains przy użyciu zestawu skrótu jest O (1) zamortyzowany (i O (log N) dla zestawu drzew) Collectors.toSet() zwraca zestaw skrótu. –

-3

Lista przecinają = list1.stream() filtr (. set1 :: contains) .collect (Collectors.toList());

To zadziała, gdy T jest ciągiem, liczbą całkowitą, zmiennoprzecinkową itp. Gdzie jest równe, kod skrótu jest dość prosty. Ale jeśli T jest obiektem niestandardowym, musimy zaimplementować kod HashCode & równy

+0

ta odpowiedź, dodana rok później, nie różni się niczym od odpowiedzi głosowanych najwyżej, niż jest bardziej rozwlekła i mniej sformatowana. – harschware

Powiązane problemy