Using java Lambda to join two list on a common attribute and collect another attribute

Viewed 1280

I have two lists

List<SampleClassOne> listOne;
List<SampleClassTwo> listTwo;

public class SampleClassOne{
  private String myProperty;
  private String myOtherProperty
  //ommiting getters-setters
}

public class SampleClassTwo{
  private String myProperty;
  private String someOtherProperty
  //ommiting getters-setters
}

I want do this

List<String> someOtherPropertyList;

for(SampleClassOne One : listOne) {
    for(SampleClassTwo two : listTwo) {
        if (one.getMyProperty().equals(two.getMyProperty())){
            someOtherPropertyList.add(two.getSomeOtherProperty());             
        }
    }
}

return someOtherPropertyList;

Can I do everything after the "I want do this" using Lambdas in an efficient way?

4 Answers

I recomend think about performance and write as following:

Collection<String> myPropertiesFromListOne = listOne.stream()
            .map(SampleClassOne::getMyProperty)
            .collect(Collectors.toSet()); // removes duplicated elements

 List<String> someOtherPropertyList = listTwo.stream()
            .filter(sampleClassTwo ->
                 myPropertiesFromListOne.contains(sampleClassTwo.getMyProperty())
            )
            .map(SampleClassTwo::getSomeOtherProperty)
            .collect(Collectors.toList());

Not particularly efficient, but you can use streams for a more declarative approach:

List<String> someOtherPropertyList = listTwo.stream()
        .filter(two -> listOne.stream()
                .map(SampleClassOne::getMyProperty)
                .anyMatch(two.getMyProperty()::equals))
        .map(SampleClassTwo::getSomeOtherProperty)
        .collect(Collectors.toList());

something like this (I hope I did not miss any parenthesis as I have not compiled this)

listTwo.stream()
      .filter(left -> listOne.stream()
            .anyMatch(right -> left.getMyProperty().equals(right.getMyProperty())))
      .map(SampleClassTwo::getSomeOtherProperty)
      .collect(Collectors.toList());  

On overwriting the hash function to return the hash of myProperty, you can do the following. (Might be slidley more efficient then iterating lists.)

new HashSet<>(listOne).addAll(listTwo)
                      .stream()
                      .forEach(someOtherPropertyList.add(someOtherProperty));
return someOtherPropertyList;
Related