Combine two list based on result data to create a new list in java 8

Multi tool use
Combine two list based on result data to create a new list in java 8
I want to combine two lists into a single list based on certain criteria.
Sample is the list 1 contains
final Org ro1= new Org(1, 1001, "Name 01");
final Org ro2 = new Org (2, 1001, "Name 02");
final Org ro3 = new Org (3, 1002, "Name 03");
final Org ro4 = new Org (4, 1003, "Name 04");
final Org ro5 = new Org (5, 1004, "Name 05");
List<Org> listOrg = new ArrayList<>();
// Add all the object to the listOrg
The list 2 contains
final Candidate can1 = new Candidate(1001, "Candidate01", "100");
final Candidate can2 = new Candidate(1002, "Candidate02", "150");
final Candidate can3 = new Candidate(1003, "Candidate03", "200");
List<Candidate > listCandidate = new ArrayList<>();
// Add all the Candidate object to the listCandidate
My final list will look like
List<Result > listResult = new ArrayList<>();
// Each individual object of the listResult is followed-
final Result rs1= new Result (1, 1001, "Name 01", "Candidate01", "100");
final Result rs2 = new Result (2, 1001, "Name 02", "Candidate01", "100");
final Result rs3 = new Result (3, 1002, "Name 03", "Candidate02", "150");
final Result rs4 = new Result (4, 1003, "Name 04", "Candidate03", "200");
final Result rs5 = new Result (5, 1004, "Name 05", null, null);
I want to achieve the same using Java 8 stream features. Can anyone please help me in this?
My class details
public class Candidate {
private int canId;
private String candidateName;
private String score;
//Getter setter with constructors.
}
public class Org{
private int id;
private int canId;
private String name;
//Getter setter with constructors
}
public class Result {
private int id;
private int canId;
private String name;
private String candidateName;
private String score;
//Getter setter with constructors.
}
The Org class have a canId, which serves as the mapping point for the CandidateClass.
new Result
@azro my mistake..editing the corect one
– Happy
Jul 2 at 7:18
Apparently, there is a property in
Org
that is supposed to match a property in Candidate
. Are we supposed to guess such relationship, as well as the property names?– Holger
Jul 2 at 7:21
Org
Candidate
show us what have you tried till now and where are you stuck?
– gagan singh
Jul 2 at 7:22
Seriously, I would simply use the traditional double
for
loop for this. Using stream API with lambdas for this is more likely to make things more complicated.– Jai
Jul 2 at 7:33
for
2 Answers
2
You can do it like so,
Map<Integer, Candidate> candidateById = listCandidate.stream()
.collect(Collectors.toMap(Candidate::getId, Function.identity()));
List<Result> resultList = listOrg.stream()
.map(o -> {
Candidate candidate = candidateById.getOrDefault(o.getCandidateId(), new Candidate(-1, null, null));
return new Result(o.getId(), o.getCandidateId(), o.getName(), candidate.getName(), candidate.getNum());
})
.collect(Collectors.toList());
First create a Map
of Candidate
objects against their Id value. Then iterate over the List
of Org
objects, get the associated Candidate
instance from the map given the Id value, and merge them together to form a Result
. Finally collect all the Results
into a List
.
Map
Candidate
List
Org
Candidate
Result
Results
List
Update
As per the comment below, this can further be improved as,
List<Result> resultList = listOrg.stream()
.map(o -> new Result(o, candidateById.get(o.getCandidateId())))
.collect(Collectors.toList());
The Result
constructor now looks like this,
Result
public Result(Org org, Candidate candidate) {
super();
this.orgId = org.getId();
this.candidateId = org.getCandidateId();
this.orgName = org.getName();
this.candidateName = Optional.ofNullable(candidate).map(c -> c.getName()).orElse(null);
this.candidateNum = Optional.ofNullable(candidate).map(c -> c.getNum()).orElse(null);
}
This cannot solve the
null
case, it'll throw NPE on .getName()– azro
Jul 2 at 7:37
null
I have updated the answer, so that it can handle
null
now.– Ravindra Ranwala
Jul 2 at 8:00
null
Now if
Result
had a constructor accepting an Org
argument and a Candidate
argument that is allowed to be null
, the code could be really elegant…– Holger
Jul 2 at 11:42
Result
Org
Candidate
null
@Holger I have updated the answer. That simplified the code significantly. Thanks a lot for the great feedback !
– Ravindra Ranwala
Jul 2 at 14:09
Thanks @RavindraRanwala for the solution. Have tried the same and works fine!
– Happy
Jul 3 at 5:45
You iterate over your Org
and for each one you look for the corresponding Candidate
if it exists, and then build a Result
from both Org
and Candidate
, a constructor Result(Org o, Candidate c)
would be helpful as you can see below :
Org
Candidate
Result
Org
Candidate
Result(Org o, Candidate c)
To avoid to iterate the listCandidate
each time, you can prepare them in a map to get them by canId
listCandidate
canId
1. Detailled solution
Map<Integer, Candidate> candidates = listCandidate.stream()
.collect(Collectors.toMap(Candidate::getCanId, Function.identity()));
List<Result > listResult = new ArrayList<>();
listOrg.forEach(org -> {
Candidate can = candidates.getOrDefault(ro.getCanId(), null);
Result r = new Result(org, can);
listResult.add(r);
});
2. Short solution using Streams
Streams
Map<Integer, Candidate> candidates = listCandidate.stream()
.collect(Collectors.toMap(Candidate::getCanId, Function.identity()));
List<Result > listResult = listOrg.stream()
.map(org -> new Result(org, candidates.getOrDefault(ro.getCanId(), null)))
.collect(Collectors.toList());
3. Result
constructor to add
Result
public Result(Org o, Candidate c){
this.id = org.getId();
this.canId = org.getCanId();
this.name = org.getName();
this.candidateName = c==null ? null : c.getCandidateName(); // return null if c is null
this.score = c==null ? null : c.getScore()); // return null if c is null
}
That implies up to
listOrg.size()
×listCandidate.size()
operations. Surely not recommended for larger lists.– Holger
Jul 2 at 11:40
listOrg.size()
listCandidate.size()
By clicking "Post Your Answer", you acknowledge that you have read our updated terms of service, privacy policy and cookie policy, and that your continued use of the website is subject to these policies.
Not
new Result
for last block code ?– azro
Jul 2 at 7:17