Extraia objetos duplicados a partir de uma lista em Java 8

Marco Tulio Avila Ceron:

Este código remove duplicatas da lista original, mas eu quero extrair as duplicatas da lista original -> não removê-los (este nome do pacote é apenas parte de outro projeto):

Dado:

uma pessoa POJO:

package at.mavila.learn.kafka.kafkaexercises;

import org.apache.commons.lang3.builder.ToStringBuilder;

public class Person {

private final Long id;
private final String firstName;
private final String secondName;


private Person(final Builder builder) {
    this.id = builder.id;
    this.firstName = builder.firstName;
    this.secondName = builder.secondName;
}


public Long getId() {
    return id;
}

public String getFirstName() {
    return firstName;
}

public String getSecondName() {
    return secondName;
}

public static class Builder {

    private Long id;
    private String firstName;
    private String secondName;

    public Builder id(final Long builder) {
        this.id = builder;
        return this;
    }

    public Builder firstName(final String first) {
        this.firstName = first;
        return this;
    }

    public Builder secondName(final String second) {
        this.secondName = second;
        return this;
    }

    public Person build() {
        return new Person(this);
    }


}

@Override
public String toString() {
    return new ToStringBuilder(this)
            .append("id", id)
            .append("firstName", firstName)
            .append("secondName", secondName)
            .toString();
}
}

código de extração duplicação.

Observe aqui que filtrar o id eo primeiro nome para recuperar uma nova lista, eu vi isso em algum lugar código de outra pessoa, não a minha:

package at.mavila.learn.kafka.kafkaexercises;

import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.concurrent.ConcurrentHashMap;
import java.util.function.Function;
import java.util.function.Predicate;
import java.util.stream.Collectors;

import static java.util.Objects.isNull;

public final class DuplicatePersonFilter {


private DuplicatePersonFilter() {
    //No instances of this class
}

public static List<Person> getDuplicates(final List<Person> personList) {

   return personList
           .stream()
           .filter(duplicateByKey(Person::getId))
           .filter(duplicateByKey(Person::getFirstName))
           .collect(Collectors.toList());

}

private static <T> Predicate<T> duplicateByKey(final Function<? super T, Object> keyExtractor) {
    Map<Object,Boolean> seen = new ConcurrentHashMap<>();
    return t -> isNull(seen.putIfAbsent(keyExtractor.apply(t), Boolean.TRUE));

}

}

O código de teste. Se você executar este caso de teste você receberá [alex, lolita, elpidio, romualdo].

Eu esperaria para chegar em vez [romualdo, otroRomualdo] como as duplicatas extraídos dado o id eo firstName:

package at.mavila.learn.kafka.kafkaexercises;


import org.junit.Test;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.util.ArrayList;
import java.util.List;

import static org.junit.Assert.*;

public class DuplicatePersonFilterTest {

private static final Logger LOGGER = LoggerFactory.getLogger(DuplicatePersonFilterTest.class);



@Test
public void testList(){

    Person alex = new Person.Builder().id(1L).firstName("alex").secondName("salgado").build();
    Person lolita = new Person.Builder().id(2L).firstName("lolita").secondName("llanero").build();
    Person elpidio = new Person.Builder().id(3L).firstName("elpidio").secondName("ramirez").build();
    Person romualdo = new Person.Builder().id(4L).firstName("romualdo").secondName("gomez").build();
    Person otroRomualdo = new Person.Builder().id(4L).firstName("romualdo").secondName("perez").build();


    List<Person> personList = new ArrayList<>();

    personList.add(alex);
    personList.add(lolita);
    personList.add(elpidio);
    personList.add(romualdo);
    personList.add(otroRomualdo);

    final List<Person> duplicates = DuplicatePersonFilter.getDuplicates(personList);

    LOGGER.info("Duplicates: {}",duplicates);

}

}

No meu trabalho eu era capaz de obter o resultado desejado lo usando Comparador usando TreeMap e ArrayList, mas esta foi a criação de uma lista, em seguida, filtrá-la, passando o filtro novamente para uma lista recém-criado, este código inchado aparência, (e provavelmente ineficiente)

Será que alguém tem uma idéia melhor como extrair duplicatas ?, não removê-los.

Desde já, obrigado.

atualização :

Obrigado a todos por suas respostas

Para remover o duplicado utilizando mesma abordagem com os uniqueAttributes:

 public static List<Person> removeDuplicates(final List<Person> personList) {

    return personList.stream().collect(Collectors
            .collectingAndThen(Collectors.toCollection(() -> new TreeSet<>(Comparator.comparing(
                    PersonListFilters::uniqueAttributes))),
                    ArrayList::new));

}

 private static String uniqueAttributes(Person person){

    if(Objects.isNull(person)){
        return StringUtils.EMPTY;
    }



    return (person.getId()) + (person.getFirstName()) ;
}
Magnilex:

Para duplicatas identificar, nenhum método que eu conheço é mais adequado do que Collectors.groupingBy(). Isso permite que você agrupe a lista em um mapa com base em uma condição de sua escolha.

Sua condição é uma combinação de ide firstName. Vamos extrair essa parte em um método próprio em Person:

String uniqueAttributes() {
  return id + firstName;
}

O getDuplicates()método agora é bastante simples:

public static List<Person> getDuplicates(final List<Person> personList) {
  return getDuplicatesMap(personList).values().stream()
      .filter(duplicates -> duplicates.size() > 1)
      .flatMap(Collection::stream)
      .collect(Collectors.toList());
}

private static Map<String, List<Person>> getDuplicatesMap(List<Person> personList) {
  return personList.stream().collect(groupingBy(Person::uniqueAttributes));
}
  • A primeira linha chama outro método getDuplicatesMap()para criar o mapa, como explicado acima.
  • Em seguida, córregos sobre os valores do mapa, que são listas de pessoas.
  • Ele filtra tudo, exceto listas com um tamanho maior do que 1, ou seja, ele encontra as duplicatas.
  • Finalmente, flatMap()é usado para nivelar o fluxo de listas em um único fluxo de pessoas, e coleta o fluxo para uma lista.

Uma alternativa, se você identificar verdadeiramente as pessoas como iguais se a ter o mesmo ide firstNameé ir com a solução por Jonathan Johx e implementar um equals()método.

Acho que você gosta

Origin http://43.154.161.224:23101/article/api/json?id=167830&siteId=1
Recomendado
Clasificación