Saltar al contenido

Eliminar duplicados de una lista de objetos según la propiedad en Java 8

Solución:

Puede obtener una transmisión desde el List y poner en el TreeSet a partir del cual proporcionas un comparador personalizado que compara id de forma única.

Luego, si realmente necesita una lista, puede volver a colocar esta colección en una 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));

Dado el ejemplo:

List<Employee> employee = Arrays.asList(new Employee(1, "John"), new Employee(1, "Bob"), new Employee(2, "Alice"));

Saldrá:

[Employee{id=1, name="John"}, Employee{id=2, name="Alice"}]

Otra idea podría ser usar un contenedor que envuelva a un empleado y tenga el método equals y hashcode basado en su 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());
    }
}

Luego envuelve cada instancia, llama distinct(), desenvolverlos y recopilar el resultado en una lista.

List<Employee> unique = employee.stream()
                                .map(WrapperEmployee::new)
                                .distinct()
                                .map(WrapperEmployee::unwrap)
                                .collect(Collectors.toList());

De hecho, creo que puede hacer que este contenedor sea genérico proporcionando una función que hará la comparación:

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));
    }
}

y el mapeo será:

.map(e -> new Wrapper<>(e, Employee::getId))

La forma más sencilla de hacerlo directamente en la lista es

HashSet<Object> seen=new HashSet<>();
employee.removeIf(e->!seen.add(e.getID()));
  • removeIf eliminará un elemento si cumple con los criterios especificados
  • Set.add volverá false si no modificó el Set, es decir, ya contiene el valor
  • combinando estos dos, eliminará todos los elementos (empleados) cuya identificación se haya encontrado antes

Por supuesto, solo funciona si la lista admite la eliminación de elementos.

Si puedes hacer uso de equals, luego filtre la lista usando distinct dentro de una secuencia (vea las respuestas arriba). Si no puede o no quiere anular la equals método, puedes filter el flujo de la siguiente manera para cualquier propiedad, por ejemplo, para el Nombre de la propiedad (lo mismo para el Id de la propiedad, etc.):

Set<String> nameSet = new HashSet<>();
List<Employee> employeesDistinctByName = employees.stream()
            .filter(e -> nameSet.add(e.getName()))
            .collect(Collectors.toList());
¡Haz clic para puntuar esta entrada!
(Votos: 0 Promedio: 0)



Utiliza Nuestro Buscador

Deja una respuesta

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *