Map to List after filtering on Map's key using Java8 stream
Asked Answered
L

4

10

I have a Map<String, List<String>>. I want to transform this map to a List after filtering on the map's key.

Example:

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

Given a key, say, "B"

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

This is what I am trying:

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

I am getting an error. Can someone provide me with a way to do it in Java8?

Lees answered 18/7, 2017 at 21:13 Comment(4)
Well, first off, what error are you getting?Bowen
Why don't you just use map.get(inputAlphabet.toUpperCase())?Metaphase
@FedericoPeraltaSchaffner I assume because the Map might contains lower case letters also in general, this being just an example...Therefore
@Therefore Yes, I also think that this is a simplified example. I just commented so that OP has the chance to improve it.Metaphase
B
17

Your sniplet wil produce a List<List<String>> not List<String>.

You are missing flatMap , that will convert stream of lists into a single stream, so basically flattens your stream:

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

You can also add distinct(), if you don't want values to repeat.

Brisk answered 18/7, 2017 at 21:17 Comment(6)
I am getting "not-static method cannot be referenced from a static context" compilation error on .flatMap(List::stream) lineTound
Is your map value of type List,Set? Here words is of Map<String, List<String>> type. What is your words collection type?Brisk
I have Map<String, Object>. I tried the same code as mentioned above and getting the compilation error.Tound
This Map is coming from another class and I know the values will always be List<String> for a specific key.Tound
I tried below and it worked. Is it because fo casting? List<String> l = map.entrySet().stream() .map(Map.Entry::getValue) .filter(c -> c instanceof Collection) .map(c -> (Collection<String>)c) .flatMap(Collection::stream) .collect(Collectors.toList());Tound
Yes, it's because of casting. You are doing a safe casting, so it will work.Brisk
T
4

Federico is right in his comment, if all you want is to get the values of a certain key (inside a List) why don't you simply do a get (assuming all your keys are uppercase letters already) ?

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

If on the other hand this is just to understand how stream operations work, there is one more way to do it (via 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())));
Therefore answered 19/7, 2017 at 6:55 Comment(1)
Very nice to use JDK 9 collector's new featuresMetaphase
N
0

As was previously told after collect you will get List<List<String>> with only one or zero value in it. You can use findFirst instead of collect it will return you Optional<List<String>>.

Nigrosine answered 18/7, 2017 at 21:30 Comment(2)
When the map has "B" and "b" as keys, you get only one list.Aphotic
Yes, I did not pay attention to equalsIgnoreCase, if it is importand my solution won't work properly.Nigrosine
B
0
List<String> items = words.entrySet().stream()
  .filter(entry -> entry.getKey().equals("B"))
  .flatMap(entry -> entry.getValue().stream())
  .collect(Collectors.toList());
  System.out.println(items);
Byssinosis answered 7/12, 2023 at 22:19 Comment(1)
While this code may answer the question, adding a bit of explanation would greatly benefit it, especially for future readers.Troup

© 2022 - 2024 — McMap. All rights reserved.