Comment supprimer des éléments répétés d'ArrayList?

Réponses:

991

Si vous ne voulez pas de doublons dans un Collection, vous devez vous demander pourquoi vous utilisez un Collectionqui autorise les doublons. Le moyen le plus simple de supprimer des éléments répétés consiste à ajouter le contenu à un Set(qui ne permettra pas les doublons), puis à ajouter le Setdos au ArrayList:

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

Bien sûr, cela détruit l'ordre des éléments dans le ArrayList.

jonathan-stafford
la source
261
Voir également LinkedHashSet, si vous souhaitez conserver la commande.
volley
3
@Chetan trouvant tous les doublons d'ArrayList dans O (n), il est important d'avoir correctement défini la méthode des égaux sur les objets que vous avez dans la liste (pas de problème pour les nombres): 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
Une bonne pratique serait de définir des variables en utilisant les types d'interface Listet Set(au lieu des types d'implémentation ArrayListet HashSetcomme dans votre exemple).
Jonik
33
Vous pouvez nettoyer cela en utilisant new HashSet(al)au lieu de l'initialiser à vide et en appelant addAll.
ashes999
1
puis-je ajouter des règles pour définir ce qui est en double pour moi? Par exemple: lorsque mon Objecta plusieurs valeurs si deux d'entre elles se répètent, je les considère comme des doublons (d'autres valeurs peuvent être différentes) et j'utilise Set?
jean d'arme
290

Bien que la conversion ArrayListen un HashSetsupprime efficacement les doublons, si vous devez conserver l'ordre d'insertion, je vous suggère plutôt d'utiliser cette variante

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

Ensuite, si vous avez besoin de récupérer une Listréférence, vous pouvez réutiliser le constructeur de conversion.

abahgat
la source
10
LinkedHashSet offre-t-il des garanties quant à ceux parmi plusieurs doublons qui sont conservés dans la liste? Par exemple, si les positions 1, 3 et 5 sont des doublons dans la liste d'origine, pouvons-nous supposer que ce processus supprimera 3 et 5? Ou peut-être supprimer 1 et 3? Merci.
Matt Briançon
16
@Matt: oui, cela le garantit. Les documents disent: "Cette liste chaînée définit l'ordre d'itération, qui est l'ordre dans lequel les éléments ont été insérés dans l'ensemble (ordre d'insertion). Notez que l'ordre d'insertion n'est pas affecté si un élément est réinséré dans l'ensemble."
abahgat
Très intéressant. J'ai une situation différente ici. Je n'essaye pas de trier la chaîne mais un autre objet appelé AwardYearSource. Cette classe a un attribut int appelé année. Je souhaite donc supprimer les doublons en fonction de l'année. c'est-à-dire que si l'année 2010 est mentionnée plus d'une fois, je veux supprimer cet objet AwardYearSource. Comment puis je faire ça?
WowBow
@WowBow Par exemple, vous pouvez définir un objet Wrapper qui contient AwardYearSource. Et définissez cette méthode des objets Wrapper égale à basée sur le champ de l'année AwardYearSources. Ensuite, vous pouvez utiliser Set avec ces objets Wrapper.
Ondrej Bozek
@WowBow ou implémentez Comparable / Comparator
shrini1000
134

En Java 8:

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

Veuillez noter que le contrat hashCode-equals pour les membres de la liste doit être respecté pour que le filtrage fonctionne correctement.

Vitalii Fedorenko
la source
1
Comment est-ce que je fais ceci pour la distinction insensible à la casse?
StackFlowed
@StackFlowed Si vous n'avez pas besoin de conserver l'ordre de la liste, vous pouvez le addAllfaire new TreeSet<String>(String.CASE_INSENSITIVE_ORDER). Le premier élément ajouté restera dans l'ensemble, donc si votre liste contient "Chien" et "chien" (dans cet ordre), TreeSetil contiendra "Chien". Si l'ordre doit être préservé, alors avant la ligne de la réponse, mettez list.replaceAll(String::toUpperCase);.
Paul
1
Je reçois cette erreur: types incompatibles: la liste <Objet> ne peut pas être convertie en liste <String>
Samir
Il s'agit d'une solution simple en général, mais comment supprimer les doublons d'un Arraylist d'int []?
Programmeur Nooby
56

Supposons que nous ayons une liste Stringcomme:

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

Ensuite, nous pouvons supprimer les éléments en double de plusieurs manières.

Avant Java 8

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

Remarque: Si nous voulons conserver l'ordre d'insertion, nous devons utiliser LinkedHashSetà la place deHashSet

Utiliser la goyave

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

Utilisation de Java 8

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

Remarque: Si nous voulons collecter le résultat dans une implémentation de liste spécifique,LinkedList nous pouvons par exemple modifier l'exemple ci-dessus comme suit:

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

Nous pouvons parallelStreamégalement l' utiliser dans le code ci-dessus, mais il peut ne pas offrir les avantages attendus en termes de performances. Consultez cette question pour en savoir plus.

akhil_mittal
la source
Yah, Quand j'ai tapé mes commentaires précédents, j'étais dans une impression qui parallel streamsdonnera toujours de meilleures performances. Mais c'est un mythe. J'ai appris plus tard qu'il existe certains scénarios dans lesquels des flux parallèles doivent être utilisés. Dans ce scénario, les flux parallèles ne donneront pas de meilleures performances. et oui les flux parallèles peuvent ne pas donner les résultats souhaités dans certains cas. List<String> deDupStringList3 = stringList.stream().map(String::toLowerCase).distinct().collect(Collectors.toList());devrait être la solution appropriée dans ce cas
Diablo
53

Si vous ne voulez pas de doublons, utilisez un ensemble au lieu d'un List. Pour convertir un Listen un, Setvous pouvez utiliser le code suivant:

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

Si vraiment nécessaire, vous pouvez utiliser la même construction pour convertir un Setdos en un List.

Benno Richters
la source
De même au bas du fil, j'ai donné une réponse où j'utilise Set for Custom Object. Dans un cas, si quelqu'un a un objet personnalisé comme "Contact" ou "Étudiant", il peut utiliser cette réponse qui me convient.
Muhammad Adil
Le problème survient lorsque vous devez accéder spécifiquement à un élément. Par exemple, lorsque vous liez un objet à une vue d'élément de liste dans Android, vous obtenez son index. SetNe peut donc pas être utilisé ici.
TheRealChx101
Comment puis-je aborder cela lorsque la liste est une liste d'objets
jvargas
28

Vous pouvez également le faire de cette façon et préserver l'ordre:

// delete duplicates (if any) from 'myArrayList'
myArrayList = new ArrayList<String>(new LinkedHashSet<String>(myArrayList));
Nenad Bulatovic
la source
Je pense que c'est la meilleure façon de supprimer les doublons dans une liste de tableaux. Certainement recommandé. Merci @Nenad pour la réponse.
ByWaleed
25

Les flux Java 8 offrent un moyen très simple de supprimer les éléments en double d'une liste. En utilisant la méthode distincte. Si nous avons une liste de villes et que nous voulons supprimer les doublons de cette liste, cela peut être fait sur une seule ligne -

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

Comment supprimer des éléments en double d'une liste d'arrayl

infoj
la source
25

Voici un moyen qui n'affecte pas l'ordre de votre liste:

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 est la liste d'origine et l2 est la liste sans éléments répétés (assurez-vous que YourClass a la méthode equals selon ce que vous voulez représenter pour l'égalité)

stbn
la source
Cette réponse manque de deux choses: 1) Il n'utilise pas de génériques, mais des types bruts ( ArrayList<T>doivent être utilisés à la place de ArrayList) 2) La création explicite d'itérateur peut être évitée en utilisant a for (T current : l1) { ... }. Même si vous vouliez utiliser Iteratorexplicitement, iteradorest mal orthographié.
RAnders00
4
Et cette implémentation s'exécute en temps quadratique, par rapport à l'implémentation de l'ensemble de hachage lié fonctionnant en temps linéaire. (c'est-à-dire que cela prend 10 fois plus longtemps sur une liste avec 10 éléments, 10 000 fois plus longtemps sur une liste avec 10 000 éléments. L'implémentation JDK 6 pour ArrayList.contains , JDK8 impl est la même.)
Patrick M
21

Il est possible de supprimer les doublons de l'arraylist sans utiliser HashSet ou un autre arraylist .

Essayez ce code ..

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

La sortie est

Duplicates List [ABC, ABC, ABCD, ABCD, ABCE]
Distinct List [ABC, ABCD, ABCE]
CarlJohn
la source
C'est lent et vous pourriez obtenir une exception ConcurrentModificationException.
maaartinus
@maaartinus Avez-vous essayé ce code?. Il ne produira aucune exception et est également assez rapide. J'ai essayé le code avant de poster.
CarlJohn
4
Vous avez raison, ce n'est pas le cas lorsque vous parcourez le tableau au lieu de la liste. Cependant, c'est lent comme l'enfer. Essayez-le avec quelques millions d'éléments. Comparez-le ImmutableSet.copyOf(lst).toList().
maaartinus
répond à la question qui m'a été posée dans l'interview. Comment supprimer les valeurs répétées d'une liste de tableaux sans utiliser les ensembles. Thanx
Aniket Paul
En interne, indexOfitère l' lstutilisation d'une boucle for.
Patrick M
21

Il y a aussi ImmutableSetde Guava en option ( voici la documentation):

ImmutableSet.copyOf(list);
Timofey Gorshkov
la source
1
Notez qu'il existe une ImmutableSet.asList()méthode, renvoyant un ImmutableList, si vous en avez besoin en tant que List.
Andy Turner
19

cela peut résoudre le problème:

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
la source
1
J'ai mieux aimé cette solution.
Tushar Gogna
12

Probablement un peu exagéré, mais j'aime ce genre de problème isolé. :)

Ce code utilise un ensemble temporaire (pour la vérification de l'unicité) mais supprime les éléments directement dans la liste d'origine. Étant donné que la suppression d'éléments à l'intérieur d'une ArrayList peut induire une énorme quantité de copie de tableau, la méthode remove (int) est évitée.

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

Pendant que nous y sommes, voici une version pour LinkedList (beaucoup plus agréable!):

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

Utilisez l'interface de marqueur pour présenter une solution unifiée pour List:

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

EDIT: Je suppose que les trucs génériques n'ajoutent pas vraiment de valeur ici .. Oh bien. :)

volée
la source
1
Pourquoi utiliser ArrayList en paramètre? Pourquoi ne pas simplement lister? Cela ne fonctionnera-t-il pas?
Shervin Asgari,
Une liste fonctionnera absolument comme paramètre pour la première méthode répertoriée. La méthode est cependant optimisée pour une utilisation avec une liste d'accès aléatoire telle que ArrayList, donc si une LinkedList est passée à la place, vous obtiendrez de mauvaises performances. Par exemple, la définition de l'élément n: th dans une LinkedList prend du temps O (n), tandis que la définition de l'élément n: th dans une liste d'accès aléatoire (telle que ArrayList) prend O (1). Encore une fois, cependant, c'est probablement exagéré ... Si vous avez besoin de ce type de code spécialisé, il sera, espérons-le, dans une situation isolée.
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
la source
Cette implémentation ne renvoie aucun élément dans la liste à cause du dernier j--
neo7
1
Ce travail de mise en œuvre est très bien.il n'y a pas de problème derrière cela et pour cette tâche, je n'utilise qu'un seul tableau. Manash
Manash Ranjan Dakua
5

Si vous souhaitez utiliser une bibliothèque tierce, vous pouvez utiliser la méthode distinct()dans Eclipse Collections (anciennement GS Collections).

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

L'avantage d'utiliser distinct()au lieu de convertir en un ensemble puis de revenir à une liste est qu'il distinct()préserve l'ordre de la liste d'origine, en conservant la première occurrence de chaque élément. Il est implémenté en utilisant à la fois un ensemble et une liste.

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;

Si vous ne pouvez pas convertir votre liste d'origine en un type de collections Eclipse, vous pouvez utiliser ListAdapter pour obtenir la même API.

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

Remarque: je suis un committer pour les collections Eclipse.

Craig P. Motlin
la source
3

Ces trois lignes de code peuvent supprimer l'élément dupliqué d'ArrayList ou de toute collection.

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

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

Lorsque vous remplissez ArrayList, utilisez une condition pour chaque élément. Par exemple:

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

Nous obtiendrons un tableau {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10}

HarpyWar
la source
2

Si vous souhaitez conserver votre commande, il est préférable d'utiliser LinkedHashSet . Parce que si vous voulez passer cette liste à une requête d'insertion en l'itérant, l'ordre serait conservé.

Essaye ça

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

Cette conversion sera très utile lorsque vous souhaitez renvoyer une liste mais pas un ensemble.

RAM
la source
2

Code:

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

Remarque: Certainement, il y aura une surcharge de mémoire.

sambhu
la source
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
la source
1

LinkedHashSet fera l'affaire.

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

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

user1912383
la source
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
la source
1

Ceci est utilisé pour votre liste d'objets personnalisés

   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
la source
1

vous pouvez utiliser la boucle imbriquée en suivant:

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
la source
1

Comme indiqué précédemment, vous devez utiliser une classe implémentant l'interface Set au lieu de List pour être sûr de l'unicité des éléments. Si vous devez conserver l'ordre des éléments, l'interface SortedSet peut alors être utilisée; la classe TreeSet implémente cette interface.

Vinze
la source
1

Si vous utilisez le type de modèle List <T> / ArrayList <T>. J'espère que cela vous aidera.

Voici mon code sans utiliser aucune autre structure de données comme 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
la source
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
la source
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);
        }


    }
}
reddy
la source
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
la source
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
la source
0

Si vous souhaitez supprimer les doublons de ArrayList signifie trouver la logique ci-dessous,

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
la source
1
Pourquoi publieriez-vous une solution quadratique à une question qui a déjà des solutions linéaires et log-linéaires vieilles de 2 ans, qui sont également plus simples?
abarnert