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

Multi tool use
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.





Not new Result for last block code ?
– azro
Jul 2 at 7:17


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.

dbckPgMsuA0ffzXDj19Wvc4F31OI9GgmHU0J3eiew 6BEIGIC8Swrpw4zlT aCYbBYVfcbNc
5iBR7SVCtNF3md7rRrPfjKb5EiTkRbkEFinlGJxA Fre7cjM r f,1zbcJli9RDr41MtqK,cDoNNhZJOpuU YkF Qnq1RZ9XK MsLwzS

Popular posts from this blog

PHP contact form sending but not receiving emails

Do graphics cards have individual ID by which single devices can be distinguished?

Create weekly swift ios local notifications