Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Java Stream: List of objects to HashMap without duplicates

I'm trying to convert a List to Map without duplicates using a stream but I can't achieve it.

I can do it using a simple loop like this:

List<PropertyOwnerCommunityAddress> propertyOwnerCommunityAddresses = getPropertyOwnerAsList();

Map<Community, List<Address>> hashMap = new LinkedHashMap<>();

for (PropertyOwnerCommunityAddress poco : propertyOwnerCommunityAddresses) {

    if (!hashMap.containsKey(poco.getCommunity())) {
        List<Address> list = new ArrayList<>();
        list.add(poco.getAddress());
        hashMap.put(poco.getCommunity(), list);
    } else {
        hashMap.get(poco.getCommunity()).add(poco.getAddress());
    }
}

but when I try to use a stream, my mind crash.

I have to say the PropertyOwnerCommunityAddress contains two object more: Community and Address and the goal of all of this is for each community save the addresses in a key:value pair without duplicate the Community object.

Anyone can help me? Thank you!

like image 342
Joarte Avatar asked Jun 10 '20 08:06

Joarte


2 Answers

As you can have multiple Addresses per Community you can't use the toMap() collector, but you need to use groupingBy():

Map<Community, List<Address>> map = propertyOwnerCommunityAddresses.stream()
    .collect(Collectors.groupingBy(
        PropertyOwnerCommunityAddress::getCommunity,
        Collectors.mapping(
            PropertyOwnerCommunityAddress::getAddress, 
            Collectors.toList())
        )
    );

Depending on your personal preference, this can look messy and maybe more complicated than the simple for-loop, which can also be optimized:

for(PropertyOwnerCommunityAddress poco : propertyOwnerCommunityAddresses) {
    hashMap.computeIfAbsent(poco.getCommunity(), c -> new ArrayList<>()).add(poco.getAddress());
}

Depending if you only want to have unique addresses you may want to use Set, so change the Collectors.toList() to Collectors.toSet() or when you stay with your for-loop change the definition of hashMap to Map<Community, Set<Address>> and in the loop exchange new ArrayList<>() with new HashSet<>()

like image 116
Lino Avatar answered Oct 18 '22 01:10

Lino


You have to use

  • groupingBy to get the Community as key
  • mapping to get the Address as list
Map<Community, List<Address>>  hashMap = propertyOwnerCommunityAddresses.stream()
            .collect(Collectors.groupingBy(PropertyOwnerCommunityAddress::getCommunity,
                    Collectors.mapping(PropertyOwnerCommunityAddress::getAddress, Collectors.toList())));
like image 38
azro Avatar answered Oct 17 '22 23:10

azro