7

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!

1
  • 4
    Your entire loop body can be replaced with hashMap.computeIfAbsent(poco.getCommunity(), key -> new ArrayList<>()).add(poco.getAddress()); Commented Jun 10, 2020 at 8:31

2 Answers 2

7

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

Sign up to request clarification or add additional context in comments.

1 Comment

Thank you! The first stream is exaclty I was looking for!
3

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

1 Comment

Thank you! Your solution is as valid as @Lino. Thank you for you post suggestions as well

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.