10

I have two classes:

public class ClassOne {

 private String id;
 private String name;
 private String school;
 private String score; //Default score is null

 ..getters and setters..
}

public class ClassTwo {

 private String id;
 private String marks; 

 ..getters and setters..
}

And, I have two Lists of the above classes,

List<ClassOne> listOne;
List<ClassTwo> listTwo;

How can I compare two list and assign marks from listTwo to score of listOne based on the criteria if the IDs are equal. I know, we can use two for loops and do it. But I want to implement it using Java8 streams.

List<ClassOne> result = new ArrayList<>();

for(ClassOne one : listOne) {
    for(ClassTwo two : listTwo) {
        if(one.getId().equals(two.getId())) {
            one.setScore(two.getmarks());
            result.add(one);
        }
    }
}
return result;

How can I implement this using Java8 lambda and streams?

2
  • The imperative approach i.e. your current approach is the way to go unless your need to implement it using Java-8 streams is to benefit from parallelism? Commented Feb 17, 2018 at 1:30
  • Even so, you'll need to 1) measure, 2) measure, 3) measure and then ensure that turning this code into a stream version will bring benefits to your application. Otherwise, if you simply want to use streams for the sake of using it then please at least show your attempt at doing so. Commented Feb 17, 2018 at 2:01

3 Answers 3

12

Let listOne.size() is N and listTwo.size() is M. Then 2-for-loops solution has complexity of O(M*N).

We can reduce it to O(M+N) by indexing listTwo by ids.

Case 1 - assuming listTwo has no objects with the same id

// pair each id with its marks
Map<String, String> marksIndex = listTwo.stream().collect(Collectors.toMap(ObjectTwo::getId, ObjectTwo::getMarks));
// go through list of `ObjectOne`s and lookup marks in the index
listOne.forEach(o1 -> o1.setScore(marksIndex.get(o1.getId())));

Case 2 - assuming listTwo has objects with the same id

    final Map<String, List<ObjectTwo>> marksIndex = listTwo.stream()
            .collect(Collectors.groupingBy(ObjectTwo::getId, Collectors.toList()));

    final List<ObjectOne> result = listOne.stream()
            .flatMap(o1 -> marksIndex.get(o1.getId()).stream().map(o2 -> {
                // make a copy of ObjectOne instance to avoid overwriting scores
                ObjectOne copy = copy(o1);
                copy.setScore(o2.getMarks());
                return copy;
            }))
            .collect(Collectors.toList());

To implement copy method you either need to create a new object and copy fields one by one, but in such cases I prefer to follow the Builder pattern. It also results in more "functional" code.

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

5 Comments

You're assuming that no ObjectTwos in listTwo share the same ID, which may be false.
that's true, let me see if I can generalise the solution to the possibility of duplicates
what if i set the properties in o1 itself and not create a copy of object ?
@HarishGupta then you'll get duplicate records in your result. And the result won't contain all marks that are present in listTwo.
@Devstr i have tried and result is not giving me the duplicate records.
3

Following code copies marks from ObjectTwo to score in ObjectOne, if both ids are equal, it doesn't have intermediate object List<ObjectOne> result

listOne.stream()
    .forEach(one -> {listTwo.stream()
        .filter(two -> {return two.getId().equals(one.getId());})
        .limit(1)
        .forEach(two -> {one.setScore(two.getMarks());});
    });

Comments

2

This should work.

Map<String, String> collect = listTwo.stream().collect(Collectors.toMap(ObjectTwo::getId, ObjectTwo::getMarks));
listOne
   .stream()
   .filter(item -> collect.containsKey(item.getId()))
   .forEach(item -> item.setScore(collect.get(item.getId())));

Comments

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.