Как фильтровать карту по ее значениям в Java 8?

У меня есть карта, где значения представляют собой строки, а ключи - это списки: Map<String, List<BoMLine>> materials. Я хотел бы отфильтровать эту карту по ее значениям; что-то вроде этого:

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

Но это не работает для меня. У кого-нибудь есть идея?

Спасибо.

Ответ 1

Если я правильно понимаю ваши критерии фильтрации, вы хотите проверить, есть ли у фильтрованного Stream вы создали из List значений, какие-либо элементы, и если да, передайте соответствующую запись Map на выходную 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()));

Это предполагает, что MaterialDao.findMaterialByName(l.getMaterial()) возвращает boolean.

Ответ 2

Как правило, вы можете фильтровать карту по ее значениям:

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

Назовите это так:

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

Ответ 3

наконец, заставило его работать, мой второй фильтр был совершенно бесполезен, ответ таков:

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