Reputation: 143
I have a user defined object called Employee like below and have two different lists which contains the Employee objects.
In the two different lists I need to findout unique object based on the name field in the object. Final list should contain only one object which the name is c.
Please suggest me how to do it using java 8?
import java.util.ArrayList;
import java.util.List;
class Employee{
private String name;
private String age;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getAge() {
return age;
}
public void setAge(String age) {
this.age = age;
}
}
public class UniqueObjects {
public static void main(String[] args) {
List<Employee> empOneList= new ArrayList<Employee>();
List<Employee> empTwoList= new ArrayList<Employee>();
Employee empOne= new Employee();
empOne.setName("a");
empOne.setAge("23");
empOneList.add(empOne);
Employee emptwo= new Employee();
emptwo.setName("b");
emptwo.setAge("24");
empOneList.add(emptwo);
Employee em= new Employee();
em.setName("a");
em.setAge("23");
empTwoList.add(em);
Employee emp1= new Employee();
emp1.setName("d");
emp1.setAge("24");
empTwoList.add(emp1);
}
}
Upvotes: 1
Views: 2547
Reputation: 4555
If I understand your question correctly, you are looking for the elements that only appear in one of the lists, but not in both. This is called the disjunctive union. There is a very easy way to retrieve it using Collection.removeAll()
:
public static <T> Set<T> getDisjunctiveUnion(Set<T> set1, Set<T> set2)
{
Collection<T> copy1 = new HashSet<>(set1);
Collection<T> copy2 = new HashSet<>(set2);
copy1.removeAll(set2);
copy2.removeAll(set1);
copy1.addAll(copy2);
return copy1;
}
Note that this requires equals
and hashCode
to be implemented for Employee
based on name
(your IDE will do this for you):
@Override
public int hashCode()
{
final int prime = 31;
int result = 1;
result = prime * result + ((name == null) ? 0 : name.hashCode());
return result;
}
@Override
public boolean equals(Object obj)
{
if (this == obj) return true;
if (obj == null) return false;
if (getClass() != obj.getClass()) return false;
Employee other = (Employee) obj;
if (name == null && other.name != null) return false;
else if (!name.equals(other.name)) return false;
return true;
}
If you do not want to implement those methods, you can use the new method Collection.removeIf()
:
copy1.removeIf(emp1 -> set2.stream().anyMatch(emp2 -> emp2.getName().equals(emp1.getName())));
copy2.removeIf(emp2 -> set1.stream().anyMatch(emp1 -> emp1.getName().equals(emp2.getName())));
Or, instead of copy/remove you use stream to filter the sets (be careful to use noneMatch
instead of anyMatch
):
Collection<Employee> disjunctiveUnion = new HashSet<>();
set1.stream()
.filter(emp1 -> set2.stream().noneMatch(emp2 -> emp2.getName().equals(emp1.getName())))
.forEach(disjunctiveUnion::add);
set2.stream()
.filter(emp2 -> set1.stream().noneMatch(emp1 -> emp1.getName().equals(emp2.getName())))
.forEach(disjunctiveUnion::add);
return disjunctiveUnion;
Upvotes: 0
Reputation: 2272
To findout unique object based on the name field you can use following code:
Map<String, List<Employee>> employeeMap = Stream.concat(empOneList.stream(), empTwoList.stream())
.collect(Collectors.groupingBy(Employee::getName, Collectors.toList()));
Using Guava
Collection<List<Employee>> employeesWithUniqueName =
Maps.filterValues(employeeMap, empList -> empList.size() == 1).values();
Using Stream API
Collection<Employee> employeesWithUniqueName =
employeeMap.values().stream().filter(empList -> empList.size() == 1)
.flatMap(List::stream)
.collect(Collectors.toList());
Upvotes: 0
Reputation: 27976
I think what your asking is how to find the single employee with a given name in either of two lists. If that's the case then the simplest thing is to just stream the two lists and filter for the unique employee:
Optional<Employee> employee = Stream.concat(list1.stream(), list2.stream())
.filter(e -> e.getName().equals(name)).findAny();
If you want objects from both lists that have the name, then:
List<Employee> employees = Stream.concat(list1.stream(), list2.stream))
.filter(e -> e.getName().equals(name)).collect(Collectors.toList());
Upvotes: 2