I have the following problem: Given these classes,
class Person {
private String zip;
...
public String getZip(){
return zip;
}
}
class Region {
private List<String> zipCodes;
...
public List<String> getZipCodes() {
return zipCodes;
}
}
using the Java 8 Stream API, how do I obtain a Map<Person, List<Region>>
based on whether the Region
contains that Person
's zip code? In other words how do I group the regions by the people whose zip codes belong to those regions?
I've done it in Java 7 the old fashioned way, but now I have to migrate the code to take advantage of the new features in Java 8.
Thank you,
Impeto
Create a List by passing another list as a constructor argument. List<String> copyOflist = new ArrayList<>(list); Create a List and use addAll method to add all the elements of the source list.
The groupingBy() method of Collectors class in Java are used for grouping objects by some property and storing results in a Map instance.
In Java 8 Streams, the flatMap() method applies operation as a mapper function and provides a stream of element values. It means that in each iteration of each element the map() method creates a separate new stream. By using the flattening mechanism, it merges all streams into a single resultant stream.
The addAll() method to merge two lists The addAll() method is the simplest and most common way to merge two lists.
I suspect the cleanest way to do this -- I'm not quite happy with the other answers posted -- would be
persons.stream().collect(Collectors.toMap(
person -> person,
person -> regions.stream()
.filter(region -> region.getZipCodes().contains(person.getZip()))
.collect(Collectors.toList())));
The original answer does an unnecessary mapping with tuples, so you see there the final solution. You could remove the mapping, and simply filter directly the regions
list:
//A Set<Region> is more appropriate, IMO
.stream()
.collect(toMap(p -> p,
p -> regions.stream()
.filter(r -> r.getZipCodes().contains(p.getZip()))
.collect(toSet())));
import java.util.AbstractMap.SimpleEntry;
import static java.util.stream.Collectors.toMap;
import static java.util.stream.Collectors.toList;
...
List<Person> persons = ...;
List<Region> regions = ...;
Map<Person, List<Region>> map =
persons.stream()
.map(p -> new SimpleEntry<>(p, regions))
.collect(toMap(SimpleEntry::getKey,
e -> e.getValue().stream()
.filter(r -> r.getZipCodes().contains(e.getKey().getZip()))
.collect(toList())));
From the List<Person>
you get a Stream<Person>
. Then you map each instance to a tuple <Person, List<Region>>
that contains all the regions. From there, you collect the data in a map with the toMap
collector and, for each person, you build a List of Region
that contains the zip code of that person.
For example, given the input:
List<Person> persons = Arrays.asList(new Person("A"), new Person("B"), new Person("C"));
List<Region> regions =
Arrays.asList(new Region(Arrays.asList("A", "B")), new Region(Arrays.asList("A")));
It outputs:
Person{zip='A'} => [Region{zipCodes=[A, B]}, Region{zipCodes=[A]}]
Person{zip='B'} => [Region{zipCodes=[A, B]}]
Person{zip='C'} => []
Also I guess the zipCodes
for each Region
could be a Set
.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With