it-roy-ru.com

Карта в список после фильтрации по ключу карты с использованием потока Java8

У меня есть Map<String, List<String>>. Я хочу преобразовать эту карту в список после фильтрации по ключу карты. 

Пример:

Map<String, List<String>> words = new HashMap<>();
List<String> aList = new ArrayList<>();
aList.add("Apple");
aList.add("Abacus");

List<String> bList = new ArrayList<>();
bList.add("Bus");
bList.add("Blue");
words.put("A", aList);
words.put("B", bList);

Учитывая ключ, скажем, "B"

Expected Output: ["Bus", "Blue"]

Вот что я пытаюсь:

 List<String> wordsForGivenAlphabet = words.entrySet().stream()
    .filter(x-> x.getKey().equalsIgnoreCase(inputAlphabet))
    .map(x->x.getValue())
    .collect(Collectors.toList());

Я получаю ошибку. Может кто-нибудь предоставить мне способ сделать это в Java8?

3
user1639485

Ваш снипплет создаст List<List<String>>, а не List<String>.

Вам не хватает flatMap , который преобразует поток списков в один поток, так что в основном выровняете ваш поток:

List<String> wordsForGivenAlphabet = words.entrySet().stream()
    .filter(x-> x.getKey().equalsIgnoreCase(inputAlphabet))
    .map(Map.Entry::getValue)
    .flatMap(List::stream) 
    .collect(Collectors.toList());

Вы также можете добавить distinct(), если не хотите, чтобы значения повторялись.

12
Beri

Федерико прав в своем комментарии, если все, что вам нужно, это получить значения определенного ключа (внутри List), почему бы вам просто не сделать get (предполагая, что все ваши ключи уже являются заглавными буквами)? 

 List<String> values = words.get(inputAlphabet.toUpperCase());

Если, с другой стороны, это просто для того, чтобы понять, как работают потоковые операции, есть еще один способ сделать это (через Java-9 Collectors.flatMapping)

List<String> words2 = words.entrySet().stream()
            .collect(Collectors.filtering(x -> x.getKey().equalsIgnoreCase(inputAlphabet),
                    Collectors.flatMapping(x -> x.getValue().stream(), 
                          Collectors.toList())));
3
Eugene

Как было сказано ранее после collect, вы получите List<List<String>> только с одним или нулевым значением. Вы можете использовать findFirst вместо collect, он вернет вам Optional<List<String>>.

0
Vitalii Muzalevskyi