Come rimuovo gli elementi ripetuti da ArrayList?


Risposte:


991

Se non si desidera duplicati in a Collection, è necessario considerare il motivo per cui si sta utilizzando un Collectionduplicato che consente duplicati. Il modo più semplice per rimuovere elementi ripetuti è aggiungere il contenuto a un Set(che non consentirà duplicati) e quindi aggiungere il Setritorno a ArrayList:

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

Naturalmente, questo distrugge l'ordinamento degli elementi nel ArrayList.


260
Vedi anche LinkedHashSet, se desideri conservare l'ordine.
scarica il

3
@Chetan trova tutti i duplicati di ArrayList in O (n), è importante avere correttamente definito il metodo uguale su oggetti che hai nella lista (nessun problema per i numeri): 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
Una buona pratica sarebbe quella di definire le variabili usando i tipi di interfaccia Liste Set(invece dei tipi di implementazione ArrayListe HashSetcome nel tuo esempio).
Jonik,

33
Puoi ripulirlo usando new HashSet(al)invece di inizializzarlo su vuoto e chiamando addAll.
ashes999,

1
posso aggiungere regole per impostare ciò che è duplicato per me? Ad esempio: quando il mio Objectha diversi valori se due di essi si ripetono li considero duplicati (altri valori possono essere diversi) e uso Set?
jean d'arme,

290

Sebbene la conversione ArrayListin una HashSetrimuova efficacemente i duplicati, se è necessario preservare l'ordine di inserzione, preferirei suggerire di utilizzare questa variante

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

Quindi, se è necessario recuperare un Listriferimento, è possibile utilizzare nuovamente il costruttore della conversione.


10
LinkedHashSet fornisce garanzie su quale dei diversi duplicati è tenuto dall'elenco? Ad esempio, se le posizioni 1, 3 e 5 sono duplicate nell'elenco originale, possiamo supporre che questo processo rimuoverà 3 e 5? O forse rimuovere 1 e 3? Grazie.
Matt Briançon,

16
@Matt: sì, lo garantisce. I documenti dicono: "Questo elenco collegato definisce l'ordine di iterazione, che è l'ordine in cui gli elementi sono stati inseriti nel set (ordine di inserimento). Nota che l'ordine di inserimento non è influenzato se un elemento viene reinserito nel set."
abahgat,

Molto interessante. Ho una situazione diversa qui. Non sto cercando di ordinare String ma un altro oggetto chiamato AwardYearSource. Questa classe ha un attributo int chiamato year. Quindi voglio rimuovere i duplicati in base all'anno. vale a dire se l'anno 2010 è menzionato più di una volta, voglio rimuovere l'oggetto AwardYearSource. Come lo posso fare?
WowBow,

@WowBow Ad esempio è possibile definire l'oggetto Wrapper che contiene AwardYearSource. E definire questo oggetto Wrapper equivale al metodo basato sul campo dell'anno AwardYearSources. Quindi è possibile utilizzare Set con questi oggetti wrapper.
Ondrej Bozek,

@WowBow o implementa Comparable / Comparator
shrini1000 l'

134

In Java 8:

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

Si noti che il contratto hashCode-equals per i membri dell'elenco deve essere rispettato affinché il filtro funzioni correttamente.


1
Come posso fare per distinzione tra maiuscole e minuscole?
StackFlowed

@StackFlowed Se non è necessario per preservare l'ordine della lista si può addAlla new TreeSet<String>(String.CASE_INSENSITIVE_ORDER). Il primo elemento aggiunto rimarrà nel set, quindi se la tua lista contiene "Cane" e "cane" (in quell'ordine) TreeSetconterrà "Cane". Se l'ordine deve essere preservato, prima della riga nella risposta inserita list.replaceAll(String::toUpperCase);.
Paul

1
Ricevo questo errore: tipi incompatibili: l'elenco <Oggetto> non può essere convertito in elenco <String>
Samir

Questa è una soluzione semplice in generale, ma come si rimuovono i duplicati da un Arraylist di int []?
Programmatore Nooby,

56

Supponiamo di avere un elenco di Stringcome:

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

Quindi possiamo rimuovere elementi duplicati in più modi.

Prima di Java 8

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

Nota: se vogliamo mantenere l'ordine di inserimento, dobbiamo usarlo LinkedHashSetal posto diHashSet

Usando la Guava

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

Utilizzando Java 8

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

Nota: nel caso in cui desideriamo raccogliere il risultato in una specifica implementazione dell'elenco ad esempio LinkedList, possiamo modificare l'esempio sopra come:

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

Possiamo usare parallelStreamanche nel codice sopra, ma potrebbe non dare benefici prestazionali previsti. Controlla questa domanda per ulteriori informazioni.


Sì, quando ho scritto i miei commenti precedenti, ho avuto un'impressione che parallel streamsdarà sempre prestazioni migliori. Ma è un mito. In seguito ho appreso che ci sono alcuni scenari in cui si dovrebbero usare flussi paralleli. In questo scenario i flussi paralleli non forniranno prestazioni migliori. e sì, flussi paralleli potrebbero non dare alcuni risultati desiderati. List<String> deDupStringList3 = stringList.stream().map(String::toLowerCase).distinct().collect(Collectors.toList());dovrebbe essere la soluzione adatta in questo caso
Diablo

53

Se non vuoi duplicati, usa un Set invece di a List. Per convertire a Listin a Setpuoi usare il seguente codice:

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

Se veramente necessario, puoi usare la stessa costruzione per convertire un Setdorso in a List.


Allo stesso modo nella parte inferiore della discussione, ho dato una risposta in cui sto usando Set for Custom Object. In un caso se qualcuno ha un oggetto personalizzato come "Contatto" o "Studente" può usare quella risposta che funziona bene per me.
Muhammad Adil,

Il problema si presenta quando devi accedere in modo specifico a un elemento. Ad esempio, quando si associa un oggetto a una vista dell'elenco in Android, viene fornito il suo indice. Quindi Setnon può essere usato qui.
TheRealChx101,

Come posso avvicinarmi a questo quando l'elenco è un elenco di oggetti
jvargas,

28

Puoi anche farlo in questo modo e conservare l'ordine:

// delete duplicates (if any) from 'myArrayList'
myArrayList = new ArrayList<String>(new LinkedHashSet<String>(myArrayList));

Penso che questo sia il modo migliore per rimuovere duplicati in una ArrayList. Decisamente raccomandato Grazie @Nenad per la risposta.
ByWaleed,

25

I flussi Java 8 forniscono un modo molto semplice per rimuovere elementi duplicati da un elenco. Utilizzando il metodo distinto. Se abbiamo un elenco di città e vogliamo rimuovere i duplicati da tale elenco, è possibile farlo in un'unica riga:

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

Come rimuovere elementi duplicati da un arraylist


25

Ecco un modo che non influisce sull'ordinamento della tua 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 è l'elenco originale e l2 è l'elenco senza elementi ripetuti (assicurarsi che YourClass abbia il metodo equals in base a ciò che si desidera rappresentare per l'uguaglianza)


Questa risposta manca di due cose: 1) Non usa generici, ma tipi grezzi ( ArrayList<T>dovrebbe essere usato al posto di ArrayList) 2) La creazione esplicita di iteratori può essere evitata usando a for (T current : l1) { ... }. Anche se volevi usare Iteratoresplicitamente, iteradorè scritto male.
RAnders00,

4
E questa implementazione viene eseguita in tempi quadratici, rispetto all'implementazione di hash set collegati in esecuzione in tempi lineari. (ovvero questo richiede 10 volte di più in un elenco con 10 elementi, 10.000 volte più in un elenco con 10.000 elementi. L'implementazione di JDK 6 per ArrayList.contains , impl di JDK8 è la stessa.)
Patrick M

21

È possibile rimuovere i duplicati dall'arraylist senza utilizzare HashSet o un altro arraylist .

Prova questo codice ..

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

L'output è

Duplicates List [ABC, ABC, ABCD, ABCD, ABCE]
Distinct List [ABC, ABCD, ABCE]

È lento e potresti ottenere una ConcurrentModificationException.
maaartino,

@maaartinus Hai provato quel codice? Non produrrà alcuna eccezione, ma è anche abbastanza veloce. Ho provato il codice prima di pubblicare.
CarlJohn,

4
Hai ragione, non è come se ripetessi l'array invece dell'elenco. Tuttavia, è lento come l'inferno. Provalo con alcuni milioni di elementi. Confrontalo con ImmutableSet.copyOf(lst).toList().
maaartinus,

risponde alla domanda che mi è stata posta nell'intervista. Come rimuovere i valori ripetuti da una ArrayList senza usare Set. Grazie
Aniket Paul,

Internamente, indexOfitera l' lstutilizzo di un ciclo for.
Patrick M,


19

questo può risolvere il 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;
}

1
Questa soluzione mi è piaciuta di più.
Tushar Gogna,

12

Probabilmente un po 'eccessivo, ma mi piace questo tipo di problema isolato. :)

Questo codice utilizza un set temporaneo (per il controllo dell'unicità) ma rimuove gli elementi direttamente dall'elenco originale. Poiché la rimozione degli elementi all'interno di un ArrayList può indurre un'enorme quantità di copie degli array, si evita il metodo remove (int).

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

Mentre ci siamo, ecco una versione per LinkedList (molto più bella!):

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

Utilizzare l'interfaccia marcatore per presentare una soluzione unificata per Elenco:

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

EDIT: Immagino che la roba generica non aggiunga davvero alcun valore qui .. Oh bene. :)


1
Perché usare ArrayList nel parametro? Perché non solo Elenco? Non funzionerà?
Shervin Asgari,

Una lista sarà assolutamente lavorare come in-parametro per il primo metodo elencato. Il metodo è tuttavia ottimizzato per l'uso con un elenco di accesso casuale come ArrayList, quindi se si passa un LinkedList si otterranno prestazioni scarse. Ad esempio, l'impostazione dell'elemento n: th in un LinkedList richiede tempo O (n), mentre l'impostazione dell'elemento n: th in un elenco di accesso casuale (come ArrayList) richiede tempo O (1). Ancora una volta, tuttavia, questo è probabilmente eccessivo ... Se hai bisogno di questo tipo di codice specializzato, si spera che si trovi in ​​una situazione isolata.
scarica il

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

Questa implementazione non restituisce alcun elemento nell'elenco a causa dell'ultimo j--
neo7 del

1
Questo lavoro di implementazione va benissimo. Non c'è nessun problema alla base di questo e per questo compito sto usando solo un arraylist.Quindi questa risposta è completamente buona.Prima di dare un feedback negativo devi anche aggiungere testcase in modo che ognuno possa capire il risultato.Grazie Manash
Manash Ranjan Dakua

5

Se si desidera utilizzare una libreria di terze parti, è possibile utilizzare il metodo distinct()nelle raccolte Eclipse (precedentemente raccolte GS).

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

Il vantaggio di utilizzare distinct()invece di convertire in un set e poi di nuovo in un elenco è quello di distinct()preservare l'ordine dell'elenco originale, mantenendo la prima occorrenza di ciascun elemento. È implementato utilizzando sia un set che un elenco.

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 non riesci a convertire il tuo Elenco originale in un tipo di raccolte Eclipse, puoi utilizzare ListAdapter per ottenere la stessa API.

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

Nota: sono un committer per le raccolte Eclipse.


3

Queste tre righe di codice possono rimuovere l'elemento duplicato da ArrayList o da qualsiasi raccolta.

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

Set<Entity> s = new LinkedHashSet<Entity>(entities);
entities.clear();
entities.addAll(s);

2

Quando si riempie l'ArrayList, utilizzare una condizione per ciascun elemento. Per esempio:

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

Otterremo un array {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10}


2

Se vuoi conservare il tuo ordine, allora è meglio usare LinkedHashSet . Perché se si desidera passare questo elenco a una query di inserimento mediante iterazione, l'ordine verrà conservato.

Prova questo

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

Questa conversione sarà molto utile quando si desidera restituire un elenco ma non un set.


2

Codice:

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: sicuramente ci sarà un sovraccarico di memoria.


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

1

LinkedHashSet farà il trucco.

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

// output: 5,1,2,3,4


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]

1

Questo è usato per il tuo elenco di oggetti personalizzati

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

1

puoi usare il ciclo nidificato nel seguente modo:

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

1

Come detto prima, dovresti usare una classe che implementa l'interfaccia Set invece di Elenco per essere sicuro dell'unicità degli elementi. Se è necessario mantenere l'ordine degli elementi, è possibile utilizzare l'interfaccia SortedSet; la classe TreeSet implementa tale interfaccia.


1

Se si utilizza il tipo di modello Elenco <T> / ArrayList <T>. Spero ti sia d'aiuto.

Ecco il mio codice senza usare altre strutture di dati come set o 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--;
  }
 }
}

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

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


    }
}

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

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

0

Se desideri rimuovere i duplicati da ArrayList significa trovare la logica di seguito,

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

1
Perché pubblicare una soluzione quadratica a una domanda che ha già soluzioni lineari e log-lineari di 2 anni, che sono anche più semplici?
Abarnert,
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.