2015-11-01 40 views
13

Mam mapę, w której wartości są ciągami, a klucze są listami: Map<String, List<BoMLine>> materials. Chciałbym przefiltrować tę mapę według jej wartości; coś takiego:Jak filtrować mapę według jej wartości w języku Java 8?

materials.entrySet().stream() 
     .filter(a->a.getValue().stream() 
      .filter(l->MaterialDao.findMaterialByName(l.getMaterial()).ispresent) 

Ale to nie działa dla mnie. Czy ktoś ma pomysł?

Dziękuję.

Odpowiedz

15

Jeśli dobrze rozumiem kryteria filtrowania, chcesz sprawdzić czy filtrowane Stream ty produkowany od wartości List ma żadnych elementów, a jeśli tak, przechodzą odpowiednie Map wejścia do wyjścia Map.

Map<String, List<BoMLine>> 
    filtered = materials.entrySet() 
         .stream() 
         .filter(a->a.getValue() 
            .stream() 
            .anyMatch(l->MaterialDao.findMaterialByName(l.getMaterial()))) 
         .collect(Collectors.toMap(e->e.getKey(),e->e.getValue())); 

to zakładając MaterialDao.findMaterialByName(l.getMaterial()) zwraca boolean.

+0

Nie jestem pewien co do mojego rozwiązania i nie działa, gdy chcę go pobrać na mapę "e" nie jest t mapa jest tylko obiektem – Nazila

+1

@nazila 'e' jest' Map.Entry > '. Zrobiłem głupie błędy składniowe w wywołaniu 'collect'. Zobacz edytowaną odpowiedź. – Eran

+2

Nie trzeba używać 'filter()', wystarczy przekazać predykat jako argument do 'anyMatch()'. –

0

w końcu działać, mój drugi filtr był całkowicie bezużyteczny odpowiedź brzmi tak:

Map<String, List<BoMLine>> 
filtered = materials.entrySet() 
        .stream() 
        .filter(a -> a 
         .getValue() 
         .stream() 
         .allMatch(
          b -> MaterialDao.findMaterialByName(
            b.getMaterial()).isPresent())) 
      .collect(Collectors.toMap(p -> p.getKey(), p -> p.getValue())) 
+0

Jeśli później nie potrzebujesz mapy źródłowej i jest ona zmienna, rozważ wykonanie operacji inplace: 'materials.values ​​(). RemoveIf (a ->! A.stream(). AllMatch (b -> MaterialDao.findMaterialByName (b .getMaterial()). isPresent())) ' – Holger

8

Ogólnie, to jak można filtrować mapę przez jej wartości:

static <K, V> Map<K, V> filterByValue(Map<K, V> map, Predicate<V> predicate) { 
    return map.entrySet() 
      .stream() 
      .filter(entry -> predicate.test(entry.getValue())) 
      .collect(Collectors.toMap(Entry::getKey, Entry::getValue)); 
} 

połączeń to tak:

Map<String, Integer> originalMap = new HashMap<>(); 
originalMap.put("One", 1); 
originalMap.put("Two", 2); 
originalMap.put("Three", 3); 

Map<String, Integer> filteredMap = filterByValue(originalMap, value -> value == 2); 

Map<String, Integer> expectedMap = new HashMap<>(); 
expectedMap.put("Two", 2); 

assertEquals(expectedMap, filteredMap); 
Powiązane problemy