2017-05-21 26 views
9

Mam klasę o nazwie MonitoredData, z którą opisuje działanie, czas jego rozpoczęcia i zakończenia. Atrybuty to activityLabel, startTime, , ,. Muszę grupować i filtrować te działania, wykorzystując strumienie, działania, których całkowity czas trwania przekracza 10 godzin. Udało mi się zrobić sumę czasów trwania i grupować je według działalności z wykorzystaniem tego:Strumień filtrów strumienia Java o wartości

Map<String, Long> map4 = new HashMap<String, Long>(); 

map4 = data.stream() 
    .collect(
     Collectors.groupingBy(
      MonitoredData::getActivity, 
      Collectors.summingLong(MonitoredData::getDuration) 
     ) 
    ); //getDuration returns end Time - startTime in milliseconds 

Ale nie udało się dodać filtr. Próbowałem użyć:

.filter(Collectors.summingLong(MonitoredData::getDuration) > whatever) 

ale oczywiście to nie działa. Jak mogę rozwiązać ten problem, aby zwrócił on Map<String, Long>?

+0

Dodaj '.filter' przed operacją' collect'? –

+0

Powinieneś najpierw zmapować 'obj -> (obj, sumDuration), a następnie zastosować filtr na wynikowym obiekcie. – NiVeR

+0

Jestem na telefonie, może twoje pytanie bardziej przypomina [to] (http: // stackoverflow.com/questions/44097658/how-to-send-parameters-to-a-reference-method-in-a-stream-java-8/44098230 # 44098230)/[that] (http://stackoverflow.com/questions/44086903/how-to-add-datetime-values-in-a-streamjava/44087302 # 44087302) z wyjątkiem filtrowania. Możesz ukończyć swoje poprzez grouing/merging, a następnie filtrowanie. –

Odpowiedz

3

myślę, że to jest to, czego chciał, używając Google Guava Maps class:

Map<String, Long> map = Maps.filterValues(data.stream() 
      .collect(Collectors.groupingBy 
        (MonitoredData::getActivity, Collectors.summingLong 
          (MonitoredData::getDuration) 
        )), value -> value > 3); 

Można oczywiście napisać własną metodę filtrowania mapę takiego, ale ponieważ jest już tam, na tak popularnej bibliotece ... Jak to zrobić z czystymi strumieniami: nie wiem, ale może to będzie satysfakcjonujące.

+1

bardzo czysty! Całkowicie zapomniałem, że możesz to zrobić z guava. – Eugene

2

Dodaj poniższy kod po masz mapę:

map4.entrySet().stream() 
       .filter(a -> a.getValue() > whatever) 
       .collect(Collectors.joining()); 
4

Jak chodzi? Odpowiadam przez telefon, sam musisz wykonać test.

map = map.entrySet() 
     .stream() 
     .filter(it->TimeUnit.MILLISECONDS.toHours(it.getValue())>10) 
     .collect(Collectors.toMap(Map.Entry::getKey,Map.Entry::getValue)); 

LUB użyciu Collectors#collectingAndThen:

map4 = data.stream() 
.collect(Collectors.collectingAndThen( 
    Collectors.groupingBy(
     MonitoredData::getActivity, 
     Collectors.summingLong(MonitoredData::getDuration) 
    ), 
    r1 -> r1.entrySet().stream() 
      .filter(it->TimeUnit.MILLISECONDS.toHours(it.getValue())>10) 
      .collect(Collectors.toMap(Map.Entry::getKey,Map.Entry::getValue)) 
)); 
6

chciałbym najpierw zrobić jak zostało to już zrobione: będę zbierać strumień MonitoredData przypadkach na mapie, grupowanie według działalności i sumowanie czas trwania każdej aktywności w każdej wartości:

Map<String, Long> map4 = data.stream() 
    .collect(Collectors.groupingBy(
     MonitoredData::getActivity, 
     HashMap::new, 
     Collectors.summingLong(MonitoredData::getDuration))); 

Niuanse są takie, że używam overloaded version of Collectors.groupingBy that accepts a factory for the map, ponieważ w następnym kroku chcę usunąć wpisy, których czas trwania jest krótszy niż 10 godzin, a specyfikacja nie gwarantuje, że mapa zwrócona przez metody Collectors.groupingBy, które przyjmują jeden lub dwa argumenty, jest zmienna.

To jak bym usunąć wpisy, które nie pasują:

public static final long TEN_HOURS_MS = 10 * 60 * 60 * 1000; 

map4.values().removeIf(v -> v < TEN_HOURS_MS); 

Jeśli chcesz zrobić wszystko w jednej linii, może chcesz używać Collectors.collectingAndThen:

Map<String, Long> map4 = data.stream() 
    .collect(Collectors.collectingAndThen(
     Collectors.groupingBy(
      MonitoredData::getActivity, 
      HashMap::new, 
      Collectors.summingLong(MonitoredData::getDuration)), 
     m -> { m.values().removeIf(v -> v < TEN_HOURS_MS); return m; })); 

Tutaj użyłem Collectors.collectingAndThen, aby zmodyfikować mapę zwróconą przez Collectors.groupingBy. W funkcji wykańczania użyłem Collection.removeIf, która pobiera predykat i usuwa wszystkie wpisy pasujące do tego predykatu.

+2

Dobra robota. zasadniczo, myślę o 'removeOf' ostatniej nocy, ale nie jestem pewien, jestem na telefonie i nie mogę przetestować. a twoje sposoby jasno opisują, który czas trwania mniej niż 10 jest usuwany z mapy. –

Powiązane problemy