Reputation: 971
I have two list instances like this:
List<NameAndAge> nameAndAgeList = new ArrayList<>();
nameAndAgeList.add(new NameAndAge("John", "28"));
nameAndAgeList.add(new NameAndAge("Paul", "30"));
nameAndAgeList.add(new NameAndAge("Adam", "31"));
List<NameAndSalary> nameAndSalaryList = new ArrayList<>();
nameAndSalaryList.add(new NameAndSalary("John", 1000));
nameAndSalaryList.add(new NameAndSalary("Paul", 1100));
nameAndSalaryList.add(new NameAndSalary("Adam", 1200));
where NameAndAge
is
class NameAndAge {
public String name;
public String age;
public NameAndAge(String name, String age) {
this.name = name;
this.age = age;
}
@Override
public String toString() {
return name + ": " + age;
}
}
and NameAndSalary
is
private class NameAndSalary {
private String name;
private double salary;
public NameAndSalary(String name, double salary) {
this.name = name;
this.salary = salary;
}
@Override
public String toString() {
return name + ": " + salary;
}
}
Now, I want to create a map with key as NameAndAge
object from the first list and value as NameAndSalary
from the second list where the name is equal in both the objects.
So, when I print the map, it should look like this:
{John: 28=John: 1000.0}
{Paul: 30=Paul: 1100.0}
{Adam: 31=Adam: 1200.0}
I have tried doing this, but the end return type is 'void' so I'm stuck clueless as I am new to Streams.
nameAndAgeList
.forEach(n ->
nameAndSalaryList
.stream()
.filter(ns -> ns.name.equals(n.name))
.collect(Collectors.toList()));
Can someone please advise how can this be achieved with Java Streams API?
Upvotes: 12
Views: 6155
Reputation: 374
Without creating any intermediate object, without using a forEach
, one liner:
Map<NameAndAge, NameAndSalary> resultMap1 = nameAndAgeList.stream()
.map(nameAndAge -> nameAndSalaryList.stream()
.filter(nameAndSalary -> nameAndAge.getName().equals(nameAndSalary.getName()))
.map(nameAndSalary -> new SimpleEntry<>(nameAndAge, nameAndSalary))
.collect(Collectors.toList()).get(0))
.collect(Collectors.toMap(simpleEntry -> simpleEntry.getKey(), simpleEntry -> simpleEntry.getValue()));
You will have to add the getter
functions to the domain classes though. Accessing the properties directly might not be a good idea.
Upvotes: -2
Reputation: 583
This should work too
List<String> commonNames = nameAndAgeList
.stream()
.filter(na ->
nameAndSalaryList.anyMatch((ns) -> ns.getName().equals(na.getName()))
.collect(Collectors.toList());
Map<NameAndAge, NameAndSalary> map =
commonNames.stream().collect(Collectors.toMap(name ->
nameAndAgeList.get(name), name -> nameAndSalaryList.get(name)));
Upvotes: 0
Reputation: 6448
This should do the trick, too:
Map<NameAndAge, NameAndSalary> map = new HashMap<>();
nameAndAgeList.forEach(age -> {
NameAndSalary salary = nameAndSalaryList.stream().filter(
s -> age.getName().equals(s.getName())).
findFirst().
orElseThrow(IllegalStateException::new);
map.put(age, salary);
});
Mind that it would throw an IllegalStateException
if a matching name can't be found.
Upvotes: 1
Reputation: 393811
First of all, assuming you are going to create a HashMap
, your key class (NameAndAge
) must override equals
and hashCode()
.
Second of all, in order to be efficient, I suggest you first create a Map<String,NameAndSalary>
from the second List
:
Map<String,NameAndSalary> helper =
nameAndSalaryList.stream()
.collect(Collectors.toMap(NameAndSalary::getName,
Function.identity()));
Finally, you can create the Map
you want:
Map<NameAndAge,NameAndSalary> output =
nameAndAgeList.stream()
.collect(Collectors.toMap(Function.identity(),
naa->helper.get(naa.getName())));
Upvotes: 10