Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Remove duplicates from a list of objects based on property in Java 8 [duplicate]

Tags:

java

list

java-8

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.

like image 745
Patan Avatar asked Apr 16 '15 09:04

Patan


People also ask

How do I remove duplicate items from a list in Java 8?

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.

How do you conditionally remove duplicates?

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.


2 Answers

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)) 
like image 75
Alexis C. Avatar answered Sep 23 '22 18:09

Alexis C.


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 criteria
  • Set.add will return false if it did not modify the Set, i.e. already contains the value
  • combining these two, it will remove all elements (employees) whose id has been encountered before

Of course, it only works if the list supports removal of elements.

like image 39
Holger Avatar answered Sep 24 '22 18:09

Holger