Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Transform and filter a Java Map with streams

I have a Java Map that I'd like to transform and filter. As a trivial example, suppose I want to convert all values to Integers then remove the odd entries.

Map<String, String> input = new HashMap<>(); input.put("a", "1234"); input.put("b", "2345"); input.put("c", "3456"); input.put("d", "4567");  Map<String, Integer> output = input.entrySet().stream()         .collect(Collectors.toMap(                 Map.Entry::getKey,                 e -> Integer.parseInt(e.getValue())         ))         .entrySet().stream()         .filter(e -> e.getValue() % 2 == 0)         .collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue));   System.out.println(output.toString()); 

This is correct and yields: {a=1234, c=3456}

However, I can't help but wonder if there's a way to avoid calling .entrySet().stream() twice.

Is there a way I can perform both transform and filter operations and call .collect() only once at the end?

like image 742
Paul I Avatar asked Feb 18 '16 16:02

Paul I


People also ask

How do you filter a Stream map?

Since our filter condition requires an int variable we first need to convert Stream of String to Stream of Integer. That's why we called the map() function first. Once we have the Stream of Integer, we can apply maths to find out even numbers. We passed that condition to the filter method.

Can we convert map to Stream in Java?

Converting complete Map<Key, Value> into Stream: This can be done with the help of Map. entrySet() method which returns a Set view of the mappings contained in this map. In Java 8, this returned set can be easily converted into a Stream of key-value pairs using Set. stream() method.

What is difference between map and filter in Java Stream?

Filter takes a predicate as an argument so basically you are validating your input/collection against a condition, whereas a map allows you to define or use a existing function on the stream eg you can apply String. toUpperCase(...) etc. and transform your inputlist accordingly.

Can we use streams on map?

Yes, you can map each entry to another temporary entry that will hold the key and the parsed integer value. Then you can filter each entry based on their value. Map<String, Integer> output = input. entrySet() .


1 Answers

Yes, you can map each entry to another temporary entry that will hold the key and the parsed integer value. Then you can filter each entry based on their value.

Map<String, Integer> output =     input.entrySet()          .stream()          .map(e -> new AbstractMap.SimpleEntry<>(e.getKey(), Integer.valueOf(e.getValue())))          .filter(e -> e.getValue() % 2 == 0)          .collect(Collectors.toMap(              Map.Entry::getKey,              Map.Entry::getValue          )); 

Note that I used Integer.valueOf instead of parseInt since we actually want a boxed int.


If you have the luxury to use the StreamEx library, you can do it quite simply:

Map<String, Integer> output =     EntryStream.of(input).mapValues(Integer::valueOf).filterValues(v -> v % 2 == 0).toMap(); 
like image 156
Tunaki Avatar answered Sep 23 '22 20:09

Tunaki