Como removo elementos repetidos do ArrayList?

Respostas:

991

Se você não deseja duplicatas em a Collection, considere por que está usando uma Collectionque permita duplicatas. A maneira mais fácil de remover elementos repetidos é adicionar o conteúdo a um Set(o que não permitirá duplicatas) e, em seguida, adicionar o Setretorno ao ArrayList:

Set<String> set = new HashSet<>(yourList);
yourList.clear();
yourList.addAll(set);

Obviamente, isso destrói a ordem dos elementos no ArrayList.

jonathan-stafford
fonte
260
Consulte também LinkedHashSet, se você deseja manter o pedido.
volley
3
@Chetan encontrar todas as duplicatas de ArrayList em O (n), é importante ter método equals corretamente definido em objetos que você tem na lista (não há problema para os números): public Set<Object> findDuplicates(List<Object> list) { Set<Object> items = new HashSet<Object>(); Set<Object> duplicates = new HashSet<Object>(); for (Object item : list) { if (items.contains(item)) { duplicates.add(item); } else { items.add(item); } } return duplicates; }
Ondrej Bozek
4
Uma boa prática seria definir variáveis ​​usando os tipos de interface Liste Set(em vez dos tipos de implementação ArrayListe HashSetcomo no seu exemplo).
Jonik
33
Você pode limpar isso usando em new HashSet(al)vez de inicializá-lo para esvaziar e chamar addAll.
ashes999
1
posso adicionar regras para definir o que é duplicado para mim? Por exemplo: quando meu Objecttiver vários valores, se dois deles repetirem, considero-os duplicados (outros valores podem ser diferentes) e utilizo Set?
jean d'arme
290

Embora a conversão de ArrayListpara HashSetremove efetivamente duplicatas, se você precisar preservar o pedido de inserção, sugiro que você use essa variante

// list is some List of Strings
Set<String> s = new LinkedHashSet<>(list);

Então, se você precisar recuperar uma Listreferência, poderá usar novamente o construtor de conversões.

abahgat
fonte
10
O LinkedHashSet oferece garantias quanto a quais duplicatas são mantidas na lista? Por exemplo, se as posições 1, 3 e 5 são duplicadas na lista original, podemos assumir que esse processo removerá 3 e 5? Ou talvez remova 1 e 3? Obrigado.
Matt Briançon
16
@ Matt: sim, isso garante. Os documentos dizem: "Esta lista vinculada define a ordem da iteração, que é a ordem na qual os elementos foram inseridos no conjunto (ordem de inserção). Observe que a ordem de inserção não será afetada se um elemento for reinserido no conjunto".
Abahgat 2/05
Muito interessante. Eu tenho uma situação diferente aqui. Não estou tentando classificar String, mas outro objeto chamado AwardYearSource. Esta classe tem um atributo int chamado year. Então, eu quero remover duplicatas com base no ano. ou seja, se houver o ano de 2010 mencionado mais de uma vez, desejo remover esse objeto AwardYearSource. Como eu posso fazer isso?
WowBow
@WowBow Por exemplo, você pode definir o objeto Wrapper que contém AwardYearSource. E defina este método Wrapper objects equals com base no campo do ano AwardYearSources. Em seguida, você pode usar Definir com esses objetos Wrapper.
Ondrej Bozek
@WowBow ou implementar Comparable / Comparator
shrini1000
134

No Java 8:

List<String> deduped = list.stream().distinct().collect(Collectors.toList());

Observe que o contrato hashCode-igual para os membros da lista deve ser respeitado para que a filtragem funcione corretamente.

Vitalii Fedorenko
fonte
1
Como faço isso para distinção entre maiúsculas e minúsculas?
StackFlowed
@StackFlowed Se você não precisa para preservar a ordem da lista que puder addAllpara new TreeSet<String>(String.CASE_INSENSITIVE_ORDER). O primeiro elemento adicionado permanecerá no conjunto, portanto, se sua lista contiver "Cão" e "cachorro" (nessa ordem), TreeSetela conterá "Cão". Se a ordem deve ser preservada, antes da linha na resposta list.replaceAll(String::toUpperCase);.
Paul
1
Estou recebendo este erro: tipos incompatíveis: List <Object> não pode ser convertido para List <String>
Samir
Esta é uma solução simples em geral, mas como você remove as duplicatas de uma matriz de matrizes de int []?
Nooby Programmer 23/01
56

Suponha que tenhamos uma lista Stringcomo:

List<String> strList = new ArrayList<>(5);
// insert up to five items to list.        

Em seguida, podemos remover elementos duplicados de várias maneiras.

Antes do Java 8

List<String> deDupStringList = new ArrayList<>(new HashSet<>(strList));

Nota: Se queremos manter o pedido de inserção, precisamos usar LinkedHashSetno lugar deHashSet

Usando goiaba

List<String> deDupStringList2 = Lists.newArrayList(Sets.newHashSet(strList));

Usando Java 8

List<String> deDupStringList3 = strList.stream().distinct().collect(Collectors.toList());

Nota: Caso desejemos coletar o resultado em uma implementação de lista específica, por exemplo LinkedList, podemos modificar o exemplo acima como:

List<String> deDupStringList3 = strList.stream().distinct()
                 .collect(Collectors.toCollection(LinkedList::new));

Também podemos usar parallelStreamo código acima, mas ele pode não fornecer os benefícios esperados de desempenho. Verifique esta pergunta para mais.

akhil_mittal
fonte
Sim, quando eu digitei meus comentários anteriores, fiquei com a impressão de que parallel streamssempre apresentaria melhor desempenho. Mas é um mito. Mais tarde eu aprendi que existem certos cenários em que fluxos paralelos devem ser usados. Nesse cenário, os fluxos paralelos não oferecem melhor desempenho. e sim fluxos paralelos podem não fornecer os resultados desejados em alguns casos. List<String> deDupStringList3 = stringList.stream().map(String::toLowerCase).distinct().collect(Collectors.toList());deve ser a solução adequada neste caso
Diablo
53

Se você não deseja duplicatas, use um conjunto em vez de um List. Para converter um Listem um, Setvocê pode usar o seguinte código:

// list is some List of Strings
Set<String> s = new HashSet<String>(list);

Se realmente necessário, você pode usar a mesma construção para converter uma Setvolta em a List.

Benno Richters
fonte
Da mesma forma, na parte inferior do segmento, dei uma resposta em que estou usando Set for Custom Object. Em um caso, se alguém tiver um objeto personalizado como "Contato" ou "Aluno", pode usar essa resposta que funciona bem para mim.
Muhammad Adil
O problema surge quando você precisa acessar especificamente um elemento. Por exemplo, ao vincular um objeto a uma exibição de item de lista no Android, você recebe seu índice. Portanto, Setnão pode ser usado aqui.
TheRealChx101
Como posso abordar isso quando a lista é uma lista de objetos
jvargas 16/03
28

Você também pode fazer dessa maneira e preservar a ordem:

// delete duplicates (if any) from 'myArrayList'
myArrayList = new ArrayList<String>(new LinkedHashSet<String>(myArrayList));
Nenad Bulatovic
fonte
Eu acho que esta é a melhor maneira de remover duplicado em um ArrayList. Definitivamente recomendado. Obrigado @Nenad pela resposta.
Marcio '13/
25

Os fluxos do Java 8 fornecem uma maneira muito simples de remover elementos duplicados de uma lista. Usando o método distinto. Se temos uma lista de cidades e queremos remover duplicatas dessa lista, isso pode ser feito em uma única linha -

 List<String> cityList = new ArrayList<>();
 cityList.add("Delhi");
 cityList.add("Mumbai");
 cityList.add("Bangalore");
 cityList.add("Chennai");
 cityList.add("Kolkata");
 cityList.add("Mumbai");

 cityList = cityList.stream().distinct().collect(Collectors.toList());

Como remover elementos duplicados de uma matriz

infoj
fonte
25

Aqui está uma maneira de não afetar o pedido da sua lista:

ArrayList l1 = new ArrayList();
ArrayList l2 = new ArrayList();

Iterator iterator = l1.iterator();

while (iterator.hasNext()) {
    YourClass o = (YourClass) iterator.next();
    if(!l2.contains(o)) l2.add(o);
}

l1 é a lista original e l2 é a lista sem itens repetidos (verifique se YourClass tem o método equals de acordo com o que você deseja que seja a igualdade)

stbn
fonte
Essa resposta não tem duas coisas: 1) Ele não usa genéricos, mas tipos brutos ( ArrayList<T>devem ser usados ​​em vez de ArrayList) 2) A criação explícita do iterador pode ser evitada usando a for (T current : l1) { ... }. Mesmo se você quiser usar um Iteratorexplicitamente, iteradorestá incorreto.
precisa saber é o seguinte
4
E essa implementação é executada em tempo quadrático, comparado à implementação do conjunto de hash vinculado em execução em tempo linear. (ou seja, este leva 10 vezes mais longos numa lista com 10 elementos, 10.000 vezes mais sobre uma lista com 10.000 elementos JDK 6 implementação para. ArrayList.contains , JDK8 impl é a mesma.)
Patrick M
21

É possível remover duplicatas do arraylist sem usar o HashSet ou mais um arraylist .

Experimente este código ..

    ArrayList<String> lst = new ArrayList<String>();
    lst.add("ABC");
    lst.add("ABC");
    lst.add("ABCD");
    lst.add("ABCD");
    lst.add("ABCE");

    System.out.println("Duplicates List "+lst);

    Object[] st = lst.toArray();
      for (Object s : st) {
        if (lst.indexOf(s) != lst.lastIndexOf(s)) {
            lst.remove(lst.lastIndexOf(s));
         }
      }

    System.out.println("Distinct List "+lst);

Saída é

Duplicates List [ABC, ABC, ABCD, ABCD, ABCE]
Distinct List [ABC, ABCD, ABCE]
CarlJohn
fonte
É lento e você pode obter uma ConcurrentModificationException.
Maaartinus 18/10/2013
@maaartinus Você já tentou esse código? Ele não produzirá nenhuma exceção, além de ser bastante rápido. Eu tentei o código antes de postar.
precisa
4
Você está certo, pois não itera a matriz em vez da lista. No entanto, é lento como o inferno. Experimente com alguns milhões de elementos. Compare com ImmutableSet.copyOf(lst).toList().
Maaartinus 18/10/2013
responde à pergunta que me foi feita na entrevista. Como remover valores repetidos de um ArrayList sem usar Sets. Thanx
Aniket Paul
Internamente, indexOfitera o lstuso de um loop for.
Patrick M
21

Também existe ImmutableSetdo Guava como uma opção ( aqui está a documentação):

ImmutableSet.copyOf(list);
Timofey Gorshkov
fonte
1
Observe que existe um ImmutableSet.asList()método, retornando um ImmutableList, se você precisar de volta como a List.
Andy Turner
19

isso pode resolver o problema:

private List<SomeClass> clearListFromDuplicateFirstName(List<SomeClass> list1) {

     Map<String, SomeClass> cleanMap = new LinkedHashMap<String, SomeClass>();
     for (int i = 0; i < list1.size(); i++) {
         cleanMap.put(list1.get(i).getFirstName(), list1.get(i));
     }
     List<SomeClass> list = new ArrayList<SomeClass>(cleanMap.values());
     return list;
}
user2868724
fonte
1
Gostei mais desta solução.
Tushar Gogna
12

Provavelmente um pouco exagerado, mas eu gosto desse tipo de problema isolado. :)

Esse código usa um conjunto temporário (para a verificação de exclusividade), mas remove os elementos diretamente dentro da lista original. Como a remoção de elementos dentro de um ArrayList pode induzir uma grande quantidade de cópias de array, o método remove (int) é evitado.

public static <T> void removeDuplicates(ArrayList<T> list) {
    int size = list.size();
    int out = 0;
    {
        final Set<T> encountered = new HashSet<T>();
        for (int in = 0; in < size; in++) {
            final T t = list.get(in);
            final boolean first = encountered.add(t);
            if (first) {
                list.set(out++, t);
            }
        }
    }
    while (out < size) {
        list.remove(--size);
    }
}

Enquanto estamos nisso, aqui está uma versão para o LinkedList (muito melhor!):

public static <T> void removeDuplicates(LinkedList<T> list) {
    final Set<T> encountered = new HashSet<T>();
    for (Iterator<T> iter = list.iterator(); iter.hasNext(); ) {
        final T t = iter.next();
        final boolean first = encountered.add(t);
        if (!first) {
            iter.remove();
        }
    }
}

Use a interface do marcador para apresentar uma solução unificada para a Lista:

public static <T> void removeDuplicates(List<T> list) {
    if (list instanceof RandomAccess) {
        // use first version here
    } else {
        // use other version here
    }
}

Edição: Eu acho que o material genérico realmente não agrega valor aqui .. Oh, bem. :)

vôlei
fonte
1
Por que usar ArrayList no parâmetro? Por que não apenas listar? Isso não vai funcionar?
21430 Shervin Asgari
Uma lista funcionará absolutamente como parâmetro para o primeiro método listado. O método, no entanto, é otimizado para uso com uma lista de acesso aleatório, como ArrayList, portanto, se um LinkedList for passado, você terá um desempenho ruim. Por exemplo, definir o n: ésimo elemento em um LinkedList leva O (n) tempo, enquanto definir o n: ésimo elemento em uma lista de acesso aleatório (como ArrayList) leva O (1). Novamente, porém, isso provavelmente é um exagero ... Se você precisar desse tipo de código especializado, esperamos que esteja em uma situação isolada.
volley
10
public static void main(String[] args){
    ArrayList<Object> al = new ArrayList<Object>();
    al.add("abc");
    al.add('a');
    al.add('b');
    al.add('a');
    al.add("abc");
    al.add(10.3);
    al.add('c');
    al.add(10);
    al.add("abc");
    al.add(10);
    System.out.println("Before Duplicate Remove:"+al);
    for(int i=0;i<al.size();i++){
        for(int j=i+1;j<al.size();j++){
            if(al.get(i).equals(al.get(j))){
                al.remove(j);
                j--;
            }
        }
    }
    System.out.println("After Removing duplicate:"+al);
}
Manash Ranjan Dakua
fonte
Esta implementação retornar nenhum elemento na lista por causa da última j--
neo7
1
Este trabalho de implementação é muito bom. Não há problema por trás disso e, para esta tarefa, uso apenas uma lista de matriz. Portanto, essa resposta é totalmente boa. Manash
Manash Ranjan Dakua
5

Se você estiver disposto a usar uma biblioteca de terceiros, poderá usar o método distinct()no Eclipse Collections (anteriormente GS Collections).

ListIterable<Integer> integers = FastList.newListWith(1, 3, 1, 2, 2, 1);
Assert.assertEquals(
    FastList.newListWith(1, 3, 2),
    integers.distinct());

A vantagem de usar em distinct()vez de converter para um conjunto e depois voltar para uma lista é que distinct()preserva a ordem da lista original, mantendo a primeira ocorrência de cada elemento. É implementado usando um conjunto e uma lista.

MutableSet<T> seenSoFar = UnifiedSet.newSet();
int size = list.size();
for (int i = 0; i < size; i++)
{
    T item = list.get(i);
    if (seenSoFar.add(item))
    {
        targetCollection.add(item);
    }
}
return targetCollection;

Se você não conseguir converter sua Lista original em um tipo de Coleções Eclipse, poderá usar o ListAdapter para obter a mesma API.

MutableList<Integer> distinct = ListAdapter.adapt(integers).distinct();

Nota: Sou um colaborador das Coleções Eclipse.

Craig P. Motlin
fonte
3

Essas três linhas de código podem remover o elemento duplicado de ArrayList ou qualquer coleção.

List<Entity> entities = repository.findByUserId(userId);

Set<Entity> s = new LinkedHashSet<Entity>(entities);
entities.clear();
entities.addAll(s);
M Kaweepatt Churcharoen
fonte
2

Ao preencher o ArrayList, use uma condição para cada elemento. Por exemplo:

    ArrayList< Integer > al = new ArrayList< Integer >(); 

    // fill 1 
    for ( int i = 0; i <= 5; i++ ) 
        if ( !al.contains( i ) ) 
            al.add( i ); 

    // fill 2 
    for (int i = 0; i <= 10; i++ ) 
        if ( !al.contains( i ) ) 
            al.add( i ); 

    for( Integer i: al )
    {
        System.out.print( i + " ");     
    }

Obteremos uma matriz {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10}

HarpyWar
fonte
2

Se você deseja preservar seu pedido, é melhor usar o LinkedHashSet . Como se você deseja passar essa lista para uma consulta de inserção, iterando-a, o pedido será preservado.

Tente isto

LinkedHashSet link=new LinkedHashSet();
List listOfValues=new ArrayList();
listOfValues.add(link);

Essa conversão será muito útil quando você desejar retornar uma Lista, mas não um Conjunto.

RAM
fonte
2

Código:

List<String> duplicatList = new ArrayList<String>();
duplicatList = Arrays.asList("AA","BB","CC","DD","DD","EE","AA","FF");
//above AA and DD are duplicate
Set<String> uniqueList = new HashSet<String>(duplicatList);
duplicatList = new ArrayList<String>(uniqueList); //let GC will doing free memory
System.out.println("Removed Duplicate : "+duplicatList);

Nota: Definitivamente, haverá sobrecarga de memória.

sambhu
fonte
2
ArrayList<String> city=new ArrayList<String>();
city.add("rajkot");
city.add("gondal");
city.add("rajkot");
city.add("gova");
city.add("baroda");
city.add("morbi");
city.add("gova");

HashSet<String> hashSet = new HashSet<String>();
hashSet.addAll(city);
city.clear();
city.addAll(hashSet);
Toast.makeText(getActivity(),"" + city.toString(),Toast.LENGTH_SHORT).show();
Hardip
fonte
1

LinkedHashSet fará o truque.

String[] arr2 = {"5","1","2","3","3","4","1","2"};
Set<String> set = new LinkedHashSet<String>(Arrays.asList(arr2));
for(String s1 : set)
    System.out.println(s1);

System.out.println( "------------------------" );
String[] arr3 = set.toArray(new String[0]);
for(int i = 0; i < arr3.length; i++)
     System.out.println(arr3[i].toString());

// saída: 5,1,2,3,4

user1912383
fonte
1
        List<String> result = new ArrayList<String>();
        Set<String> set = new LinkedHashSet<String>();
        String s = "ravi is a good!boy. But ravi is very nasty fellow.";
        StringTokenizer st = new StringTokenizer(s, " ,. ,!");
        while (st.hasMoreTokens()) {
            result.add(st.nextToken());
        }
         System.out.println(result);
         set.addAll(result);
        result.clear();
        result.addAll(set);
        System.out.println(result);

output:
[ravi, is, a, good, boy, But, ravi, is, very, nasty, fellow]
[ravi, is, a, good, boy, But, very, nasty, fellow]
siva
fonte
1

Isso é usado para sua lista de objetos personalizados

   public List<Contact> removeDuplicates(List<Contact> list) {
    // Set set1 = new LinkedHashSet(list);
    Set set = new TreeSet(new Comparator() {

        @Override
        public int compare(Object o1, Object o2) {
            if (((Contact) o1).getId().equalsIgnoreCase(((Contact) o2).getId()) /*&&
                    ((Contact)o1).getName().equalsIgnoreCase(((Contact)o2).getName())*/) {
                return 0;
            }
            return 1;
        }
    });
    set.addAll(list);

    final List newList = new ArrayList(set);
    return newList;
}
Gujjula Ramesh Reddy
fonte
1

você pode usar o loop aninhado a seguir:

ArrayList<Class1> l1 = new ArrayList<Class1>();
ArrayList<Class1> l2 = new ArrayList<Class1>();

        Iterator iterator1 = l1.iterator();
        boolean repeated = false;

        while (iterator1.hasNext())
        {
            Class1 c1 = (Class1) iterator1.next();
            for (Class1 _c: l2) {
                if(_c.getId() == c1.getId())
                    repeated = true;
            }
            if(!repeated)
                l2.add(c1);
        }
HamidReza
fonte
1

Como dito anteriormente, você deve usar uma classe implementando a interface Set em vez de List para garantir a unicidade dos elementos. Se você precisar manter a ordem dos elementos, a interface SortedSet poderá ser usada; a classe TreeSet implementa essa interface.

Vinze
fonte
1

Se você estiver usando o tipo de modelo List <T> / ArrayList <T>. Espero que seja de ajuda.

Aqui está o meu código sem usar nenhuma outra estrutura de dados como set ou hashmap

for (int i = 0; i < Models.size(); i++){
for (int j = i + 1; j < Models.size(); j++) {       
 if (Models.get(i).getName().equals(Models.get(j).getName())) {    
 Models.remove(j);
   j--;
  }
 }
}
Saurabh Gaddelpalliwar
fonte
0
for(int a=0;a<myArray.size();a++){
        for(int b=a+1;b<myArray.size();b++){
            if(myArray.get(a).equalsIgnoreCase(myArray.get(b))){
                myArray.remove(b); 
                dups++;
                b--;
            }
        }
}
Ghyour
fonte
0
import java.util.*;
class RemoveDupFrmString
{
    public static void main(String[] args)
    {

        String s="appsc";

        Set<Character> unique = new LinkedHashSet<Character> ();

        for(char c : s.toCharArray()) {

            System.out.println(unique.add(c));
        }
        for(char dis:unique){
            System.out.println(dis);
        }


    }
}
avermelhado
fonte
0
public Set<Object> findDuplicates(List<Object> list) {
        Set<Object> items = new HashSet<Object>();
        Set<Object> duplicates = new HashSet<Object>();
        for (Object item : list) {
            if (items.contains(item)) {
                duplicates.add(item);
                } else { 
                    items.add(item);
                    } 
            } 
        return duplicates;
        }
Harsha
fonte
0
    ArrayList<String> list = new ArrayList<String>();
    HashSet<String> unique = new LinkedHashSet<String>();
    HashSet<String> dup = new LinkedHashSet<String>();
    boolean b = false;
    list.add("Hello");
    list.add("Hello");
    list.add("how");
    list.add("are");
    list.add("u");
    list.add("u");

    for(Iterator iterator= list.iterator();iterator.hasNext();)
    {
        String value = (String)iterator.next();
        System.out.println(value);

        if(b==unique.add(value))
            dup.add(value);
        else
            unique.add(value);


    }
    System.out.println(unique);
    System.out.println(dup);
SparkOn
fonte
0

Se você deseja remover duplicatas do ArrayList significa encontrar a lógica abaixo,

public static Object[] removeDuplicate(Object[] inputArray)
{
    long startTime = System.nanoTime();
    int totalSize = inputArray.length;
    Object[] resultArray = new Object[totalSize];
    int newSize = 0;
    for(int i=0; i<totalSize; i++)
    {
        Object value = inputArray[i];
        if(value == null)
        {
            continue;
        }

        for(int j=i+1; j<totalSize; j++)
        {
            if(value.equals(inputArray[j]))
            {
                inputArray[j] = null;
            }
        }
        resultArray[newSize++] = value;
    }

    long endTime = System.nanoTime()-startTime;
    System.out.println("Total Time-B:"+endTime);
    return resultArray;
}
Thananjayan N
fonte
1
Por que você postaria uma solução quadrática em uma pergunta que já possui soluções lineares e log-lineares de 2 anos, que também são mais simples?
abarnert