8 métodos de desduplicação de objetos de coleção de listas e desduplicação por atributos - sexta parte da série de resumo básico Java

Recentemente, estou escrevendo alguns artigos sobre noções básicas de java, mas não quero escrever artigos sobre pontos de conhecimento na forma de livros didáticos, porque é de pouca importância. Existem muitos conhecimentos básicos, como resumir esse conhecimento, resumir as vantagens e desvantagens ou cenários de uso é a sublimação do conhecimento . Portanto, gostaria de aprofundar os conhecimentos básicos de java e fazer um resumo geral.

  • Resuma 5 maneiras de criar e gravar arquivos em java
  • Resuma os 6 métodos de leitura de dados de arquivos em java
  • Resuma os 4 métodos de criação de pastas em java e suas vantagens e desvantagens
  • Resuma 7 maneiras de excluir arquivos ou pastas em java
  • Resuma 5 maneiras de copiar e cortar arquivos em java

Por exemplo, já escrevi o conteúdo acima. Se você estiver interessado na série de resumos de conhecimentos básicos de Java, pode seguir o meu blog (o endereço do meu blog é fornecido no final do artigo) .

1. Resumo deste artigo

Neste artigo, quero escrever cerca de 8 métodos para desduplicação de elementos da coleção List . Na verdade, por meio do uso flexível, pode não haver 8 permutações e combinações, mas pode haver 18 métodos.

  • 4 métodos para desduplicação geral de elementos de objeto
  • 4 maneiras de eliminar a duplicação de acordo com os atributos do objeto

Para explicar o conteúdo do teste abaixo, primeiro fazemos alguns dados de inicialização

public class ListRmDuplicate {
  private List<String> list;
  private List<Player> playerList;

  @BeforeEach
  public void setup() {
    list  =  new ArrayList<>();
    list.add("kobe");
    list.add("james");
    list.add("curry");
    list.add("zimug");
    list.add("zimug");

    playerList= new ArrayList<>();
    playerList.add(new Player("kobe","10000"));  //科比万岁
    playerList.add(new Player("james","32"));
    playerList.add(new Player("curry","30"));
    playerList.add(new Player("zimug","27"));   // 注意这里名字重复
    playerList.add(new Player("zimug","18"));   //注意这里名字和年龄重复
    playerList.add(new Player("zimug","18")); //注意这里名字和年龄重复

  }
}

O objeto Player é um objeto java comum com duas variáveis ​​de membro name e age, que implementam construtores parametrizados, métodos toString, equals e hashCode, e métodos GET / SET.

Em segundo lugar, a eliminação geral da duplicação dos elementos da coleção

Os quatro métodos a seguir eliminam a duplicação do tipo String na Lista como uma unidade do objeto do elemento da coleção como um todo. Se sua lista for um objeto Object, você precisará implementar os métodos equals e hashCode do objeto.O método de implementação de código List<String>para desduplicação é o mesmo que para desduplicação.

o primeiro método

É mais fácil para todos pensarem, primeiro coloque os dados da Lista no Conjunto, porque a própria estrutura de dados do Conjunto tem a função de desduplicação, portanto, depois que o SET é convertido para a Lista, ele é o resultado da desduplicação. Este método mudará a ordem original dos elementos List após a eliminação da duplicação, porque o próprio HashSet não está ordenado e a classificação TreeSet não é a ordem original dos elementos List.

@Test
void testRemove1()  {
  /*Set<String> set = new HashSet<>(list);
  List<String> newList = new ArrayList<>(set);*/

  //去重并排序的方法(如果是字符串,按字母表排序。如果是对象,按Comparable接口实现排序)
  //List<String> newList = new ArrayList<>(new TreeSet<>(list));

  //简写的方法
  List<String> newList = new ArrayList<>(new HashSet<>(list));

  System.out.println( "去重后的集合: " + newList);
}

Os resultados da impressão do console são os seguintes:

去重后的集合: [kobe, james, zimug, curry]

O segundo método

É relativamente simples de usar. Primeiro, use o método stream para converter a coleção em um stream, em seguida, distinta para remover as duplicatas e, finalmente, colete a coleta do stream Stream como uma Lista.

@Test
void testRemove2()  {
  List<String> newList = list.stream().distinct().collect(Collectors.toList());

  System.out.println( "去重后的集合: " + newList);
}

Os resultados da impressão do console são os seguintes:

去重后的集合: [kobe, james, curry, zimug]

O terceiro método Este método é usado set.add(T), se o elemento T já existir na coleção, ele retorna falso. Use este método para determinar se os dados estão duplicados e, se não estiverem, coloque-os em uma nova newList, esta newList é o resultado final da desduplicação

//三个集合类list、newList、set,能够保证顺序
@Test
void testRemove3()  {

  Set<String> set = new HashSet<>();
  List<String> newList = new  ArrayList<>();
  for (String str :list) {
    if(set.add(str)){ //重复的话返回false
      newList.add(str);
    }
  }
  System.out.println( "去重后的集合: " + newList);

}

O resultado da impressão do console é consistente com o segundo método.

O quarto método Este método rompeu com o pensamento de usar a coleção Set para desduplicação, mas usa um newList.contains(T)método para determinar se os dados já existem ao adicionar dados a uma nova Lista, e se não os adiciona, de modo a atingir a desduplicação Efeito.

//优化 List、newList、set,能够保证顺序
@Test
void testRemove4() {

  List<String> newList = new  ArrayList<>();
  for (String cd:list) {
    if(!newList.contains(cd)){  //主动判断是否包含重复元素
      newList.add(cd);
    }
  }
  System.out.println( "去重后的集合: " + newList);

}

O resultado da impressão do console é consistente com o segundo método.

Terceiro, elimine a duplicação de acordo com os atributos do objeto do elemento da coleção

Na verdade, no trabalho real, a aplicação da desduplicação de acordo com a desduplicação geral dos objetos do elemento da coleção ainda é relativamente pequena, e mais é que somos obrigados a desduplicação de acordo com certos atributos dos objetos do elemento. Vendo isso, por favor, volte e dê uma olhada nos dados de inicialização construídos playerListacima.Preste atenção especial a alguns dos elementos repetidos e à repetição de variáveis ​​de membro.

O primeiro método é implementar a interface Comparator para o TreeSet. Se quisermos eliminar a duplicação de acordo com o atributo de nome do Player, podemos comparar os nomes na interface Comparator. Dois métodos de implementação da interface Comparator são escritos abaixo:

  • Expressão lambda:(o1, o2) -> o1.getName().compareTo(o2.getName())
  • Referência do método:Comparator.comparing(Player::getName)
@Test
void testRemove5() {
  //Set<Player> playerSet = new TreeSet<>((o1, o2) -> o1.getName().compareTo(o2.getName()));
  Set<Player> playerSet = new TreeSet<>(Comparator.comparing(Player::getName));
  playerSet.addAll(playerList);

  /*new ArrayList<>(playerSet).forEach(player->{
    System.out.println(player.toString());
  });*/
  //将去重之后的结果打印出来
  new ArrayList<>(playerSet).forEach(System.out::println);
}

O resultado é o seguinte: três zimugs têm nomes duplicados e os outros dois são desduplicados. Mas, como TreeSet é usado, os elementos da lista são reordenados.

Player{name='curry', age='30'}
Player{name='james', age='32'}
Player{name='kobe', age='10000'}
Player{name='zimug', age='27'}

O segundo método Este método é usado em muitos artigos na Internet para mostrar que você é incrível, mas na minha opinião, tiro a calça e peido. Já que todos dizem que existe tal método, não o escrevo como se não fosse bom nisso. Por que digo que esse método é "tirar minhas calças e peidar"?

  • Primeiro use stream () para converter a coleção de listas em um stream
  • Em seguida, use collect e toCollection para converter o fluxo em uma coleção
  • Então o resto é igual ao primeiro método

Você não tirou as calças e peidou nas duas primeiras etapas? Basta dar uma olhada, a aplicação prática não é muito significativa, mas se for para aprender a usar o Stream, ainda é desejável dar um exemplo.

@Test
void testRemove6() {
  List<Player> newList = playerList.stream().collect(Collectors
          .collectingAndThen(
                  Collectors.toCollection(() -> new TreeSet<>(Comparator.comparing(Player::getName))),
                  ArrayList::new));

  newList.forEach(System.out::println);
}

A impressão do console é igual ao primeiro método.

O terceiro método

Este método também é um método que o autor recomenda que todos usem.A primeira vista, parece que a quantidade de código é maior, mas na verdade, este método é um método relativamente simples de aplicar.

Predicado (algumas pessoas chamam isso de predicado; do ponto de vista do inglês, pode ser traduzido como um predicado como um substantivo, e como um verbo pode ser traduzido como um predicado). Predicados são usados ​​para modificar o assunto, por exemplo: um pássaro que gosta de cantar é um predicado, que é usado para limitar o alcance do assunto. Então, estamos aqui para filtrar, mas também para limitar o escopo do assunto, então acho que é mais apropriado traduzir como um predicado. O que você quiser, pode fazer o que achar razoável e fácil de lembrar.

  • Primeiro, definimos um predicado Predicado para filtrar e a condição do filtro é DifferentByKey. O predicado retorna o elemento verdadeiro a ser mantido e o elemento falso é filtrado.
  • Claro, nosso requisito é filtrar elementos duplicados. Nossa lógica de eliminação de duplicação é implementada por putIfAbsent do mapa. O método putIfAbsent adiciona um par de valor-chave. Se não houver nenhum valor correspondente à chave no conjunto de mapas, adicione-o diretamente e retorne nulo. Se o valor correspondente já existir, ainda será o valor original.
  • Se putIfAbsent retornar nulo, significa que os dados foram adicionados com êxito (não repetidos). Se putIfAbsent retornar valor (valor == null: false), o elemento que atende à condição do predicado distintoByKey é filtrado.

Embora esse método pareça ter aumentado a quantidade de código, o método do predicado distinctByKey só precisa ser definido uma vez e pode ser reutilizado indefinidamente.

@Test
void testRemove7() {
  List<Player> newList = new ArrayList<>();
  playerList.stream().filter(distinctByKey(p -> p.getName()))  //filter保留true的值
          .forEach(newList::add);

  newList.forEach(System.out::println);
}

static <T> Predicate<T> distinctByKey(Function<? super T, ?> keyExtractor) {
  Map<Object,Boolean> seen = new ConcurrentHashMap<>();
  //putIfAbsent方法添加键值对,如果map集合中没有该key对应的值,则直接添加,并返回null,如果已经存在对应的值,则依旧为原来的值。
  //如果返回null表示添加数据成功(不重复),不重复(null==null :TRUE)
  return t -> seen.putIfAbsent(keyExtractor.apply(t), Boolean.TRUE) == null;
}

O resultado é o seguinte: três zimugs têm nomes duplicados e os outros dois são desduplicados. E não interrompeu a ordem original da Lista

Player{name='kobe', age='10000'}
Player{name='james', age='32'}
Player{name='curry', age='30'}
Player{name='zimug', age='27'}

O quarto método O quarto método não é realmente um método novo. Os exemplos acima são todos baseados em um determinado atributo de objeto a ser desduplicado. Se quisermos desduplicar de acordo com certos elementos, precisamos modificar os três métodos acima. . Remodelei apenas uma delas, o princípio das outras remodelações é o mesmo, ou seja, somar múltiplas propriedades de comparação e compará-las como uma propriedade String.

@Test
void testRemove8() {
  Set<Player> playerSet = new TreeSet<>(Comparator.comparing(o -> (o.getName() + "" + o.getAge())));

  playerSet.addAll(playerList);

  new ArrayList<>(playerSet).forEach(System.out::println);
}

Bem-vindo a seguir meu blog, existem muitas coleções boutique

  • Este artigo é reproduzido com a indicação da fonte (a conexão deve ser anexada, e o texto não pode ser reproduzido somente): Carta Blog da Brother .

Se você acha que é útil para você, por favor, curta e compartilhe para mim! Seu apoio é minha motivação criativa inesgotável! . Além disso, o autor produziu o seguinte conteúdo de alta qualidade recentemente e espero sua atenção.

Acho que você gosta

Origin blog.csdn.net/hanxiaotongtong/article/details/108442705
Recomendado
Clasificación