2014-04-26 30 views
7

To pytanie dotyczy mapowania i grupowania elementów za pomocą kolektorów Java 8. Mam listę pacjentów. Każdy Pacjent ma listę oddziałów, które odwiedził. Powiedz, że chcę liczyć dla każdego działu, ile czasu zostało odwiedzone przy użyciu nowego interfejsu API kolektorów w java 8, w jaki sposób mogę pogrupować według listy departamentów?Java 8 Collectors API

Dzięki!

UWAGA: wiem, że mogę umieścić licznik w każdym z działów, to pytanie jest wyłącznie do celów nauki Nowa aplikacja Java 8 możliwości.

Kod:

public class Patient { 
    private String id; 
    private List<Department> history; 
    /* some more getters/setters come here */ 
} 

W moim głównym sposobem mam listę Pacjenta. Chcę wiedzieć dla każdego Wydziału, ile czasu zostało odwiedzonych, bez edytowania klasy Wydziału (lub przedłużania lub dekorowania jej).

Myślę, że muszę wziąć strumień pacjentów i zamapować je na mapę dept-> count (ile razy każdy pacjent odwiedził który dept.). Mając strumień tych map - nie mam pojęcia, co zrobić, aby pogrupować te mapy i policzyć je.

+0

Jest to prawdopodobnie najlepiej wytłumaczyć według kodu. Zdefiniuj swój kod pacjenta i działu, aby każdy mógł się z nim zapoznać. –

+0

@owlstead: Dodałem pola klasy Pacjent. To powinno być proste. Po prostu nie mogę tego znaleźć. Zauważ, że nie dodałem kodu do działu, ponieważ nie ma on znaczenia, może być łatwo ciągiem znaków. –

Odpowiedz

11

Po pierwsze, zakładam, że jeśli Pacjent odwiedził dany Wydział więcej niż jeden raz, ten Dział pojawi się na liście historii Pacjenta więcej niż jeden raz.

Jeśli tak jest, to możemy po prostu wziąć strumień pacjentów i flatMap go do strumienia departamentów, gdzie wystąpienie działu wskazuje jedną wizytę od pacjenta.

Następnie możemy przekazać to do kolektora groupingBy. Chcemy klasyfikować według działu, więc funkcja klasyfikatora jest funkcją tożsamości.

Dla wartości, chcemy umieścić 1 jako wartość, jeśli wpis dla Departamentu jeszcze nie istnieje, ale chcemy dodać 1 do istniejącej wartości, jeśli wpis jest obecny. Jest kolekcjoner o nazwie counting(), który robi to już dla nas, więc przekazujemy go jako dalszy kolektor do groupingBy().

Otrzymany kod jest następujący:

import static java.util.stream.Collectors.*; 

List<Patient> patients = ... ; 

Map<Department, Long> frequency = 
    patients.stream() 
     .flatMap(p -> p.getHistory().stream()) 
     .collect(groupingBy(d -> d, counting())); 

Zauważ, że jeśli nie został Departament odwiedził, to po prostu być nieobecny z mapy. Jeśli masz listę działów, można wypełnić zerowych wartościach, takich jak ten:

departments.forEach(d -> frequency.putIfAbsent(d, 0L)); 

lub jeśli chcesz wypełnić zera po stronie get,

long numVisits = frequency.getOrDefault(dept, 0L); 
+0

Wygląda dość prosto i wydaje się działać. Należy jednak pamiętać, że statycznie zaimportowano kolekcjonerów. Czy mógłbyś wyjaśnić logikę rozwiązania? –

+1

@nocgod Myślę, że wpisując wyjaśnienie w tym samym czasie, o które prosiłeś.:-) –

+1

Sądzę, że byłeś :) Będę musiał zrobić mały zwrot, żeby dostać się do tego całego funkcjonalnego stylu lambda - nie dotknął go od czasu mojego kursu PPL i języka schematów. Dzięki jeszcze raz! –