I am trying to remove duplicates from a List of objects based on some property.
can we do it in a simple way using java 8
List<Employee> employee
Can we remove duplicates from it based on id
property of employee. I have seen posts removing duplicate strings form arraylist of string.
To remove the duplicates from the arraylist, we can use the java 8 stream api as well. Use steam's distinct() method which returns a stream consisting of the distinct elements comparing by object's equals() method. Collect all district elements as List using Collectors.
To remove duplicate values, click Data > Data Tools > Remove Duplicates. To highlight unique or duplicate values, use the Conditional Formatting command in the Style group on the Home tab.
You can get a stream from the List
and put in in the TreeSet
from which you provide a custom comparator that compares id uniquely.
Then if you really need a list you can put then back this collection into an ArrayList.
import static java.util.Comparator.comparingInt; import static java.util.stream.Collectors.collectingAndThen; import static java.util.stream.Collectors.toCollection; ... List<Employee> unique = employee.stream() .collect(collectingAndThen(toCollection(() -> new TreeSet<>(comparingInt(Employee::getId))), ArrayList::new));
Given the example:
List<Employee> employee = Arrays.asList(new Employee(1, "John"), new Employee(1, "Bob"), new Employee(2, "Alice"));
It will output:
[Employee{id=1, name='John'}, Employee{id=2, name='Alice'}]
Another idea could be to use a wrapper that wraps an employee and have the equals and hashcode method based with its id:
class WrapperEmployee { private Employee e; public WrapperEmployee(Employee e) { this.e = e; } public Employee unwrap() { return this.e; } @Override public boolean equals(Object o) { if (this == o) return true; if (o == null || getClass() != o.getClass()) return false; WrapperEmployee that = (WrapperEmployee) o; return Objects.equals(e.getId(), that.e.getId()); } @Override public int hashCode() { return Objects.hash(e.getId()); } }
Then you wrap each instance, call distinct()
, unwrap them and collect the result in a list.
List<Employee> unique = employee.stream() .map(WrapperEmployee::new) .distinct() .map(WrapperEmployee::unwrap) .collect(Collectors.toList());
In fact, I think you can make this wrapper generic by providing a function that will do the comparison:
public class Wrapper<T, U> { private T t; private Function<T, U> equalityFunction; public Wrapper(T t, Function<T, U> equalityFunction) { this.t = t; this.equalityFunction = equalityFunction; } public T unwrap() { return this.t; } @Override public boolean equals(Object o) { if (this == o) return true; if (o == null || getClass() != o.getClass()) return false; @SuppressWarnings("unchecked") Wrapper<T, U> that = (Wrapper<T, U>) o; return Objects.equals(equalityFunction.apply(this.t), that.equalityFunction.apply(that.t)); } @Override public int hashCode() { return Objects.hash(equalityFunction.apply(this.t)); } }
and the mapping will be:
.map(e -> new Wrapper<>(e, Employee::getId))
The easiest way to do it directly in the list is
HashSet<Object> seen=new HashSet<>(); employee.removeIf(e->!seen.add(e.getID()));
removeIf
will remove an element if it meets the specified criteriaSet.add
will return false
if it did not modify the Set
, i.e. already contains the valueOf course, it only works if the list supports removal of elements.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With