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();
Answer from Tunaki on Stack OverflowYes, 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();
One way to solve the problem with much lesser overhead is to move the mapping and filtering down to the collector.
Map<String, Integer> output = input.entrySet().stream().collect(
HashMap::new,
(map,e)->{ int i=Integer.parseInt(e.getValue()); if(i%2==0) map.put(e.getKey(), i); },
Map::putAll);
This does not require the creation of intermediate Map.Entry instances and even better, will postpone the boxing of int values to the point when the values are actually added to the Map, which implies that values rejected by the filter are not boxed at all.
Compared to what Collectors.toMap(…) does, the operation is also simplified by using Map.put rather than Map.merge as we know beforehand that we don’t have to handle key collisions here.
However, as long as you don’t want to utilize parallel execution you may also consider the ordinary loop
HashMap<String,Integer> output=new HashMap<>();
for(Map.Entry<String, String> e: input.entrySet()) {
int i = Integer.parseInt(e.getValue());
if(i%2==0) output.put(e.getKey(), i);
}
or the internal iteration variant:
HashMap<String,Integer> output=new HashMap<>();
input.forEach((k,v)->{ int i = Integer.parseInt(v); if(i%2==0) output.put(k, i); });
the latter being quite compact and at least on par with all other variants regarding single threaded performance.
It would be more appropriate to use the forEach method here rather than map. Map is for transforming one piece of data into another, forEach is for doing an operation on each element of the stream which is what's happening here.
The Stream.map() accepts the instance of Function interface. The problem is that most likely person.setAge() returns void, and therefore javac (Java most famous compiler, most likely you are using it), that is trying to infer the exact functional interface being used in lambda, cannot infer Function, since setAge returns void. In order to fix it, make setAge return this, such as:
public Person setAge(int age) {
this.age = age;
return this;
}
UPDATE:
As noted in the comments, in your exact scenario usage of map() is not recommended. You can just use forEach() that accepts the Consumer.
So I have a Map <Long, Ingredient> normalMap and my method needs to first invert the keys&values and lastly return the map as Map <String, Long>
To invert the map I wrote the following code:
invertedMap = normalMap.entrySet().stream().collect(Collectors.toMap(Map.Entry::getValue, Map.Entry::getKey));
So far, so good.
Now I need to make my inverted Map return the Name of my Object as a String. Note: My Ingredient Object has a @ Override method which overrides the toString() method and basically return the getter method { this.getName(); }
So what my idea was to write the following code:
return invertedMap.entrySet().stream().collect(Collectors.toMap(Ingredient::toString, Function.identity()));
Unfortunately, this does not work. I'm googling and trying to find a solution and whenever I find something useful it creates new errors. Pls help.
Update: I managed to make it work using following code:
Map<String, Long> ingToString = new HashMap<>();
for (Map.Entry<Ingredient, Long> entry : invertedMap.entrySet())
{
Ingredient ing = entry.getKey();
ingToString.put(entry.getKey().toString(), entry.getValue());
}
return ingToString;But my question still is, what is the equivalent to this code but using .stream() ?