Comment supprimer les doublons d'un tableau C #?


209

J'ai travaillé avec un string[]tableau en C # qui est renvoyé par un appel de fonction. Je pourrais éventuellement caster dans une Genericcollection, mais je me demandais s'il y avait une meilleure façon de le faire, éventuellement en utilisant un tableau temporaire.

Quelle est la meilleure façon de supprimer les doublons d'un tableau C #?


4
Utilisez la méthode d'extension Distinct.
kokos

En effet. C'est plus amusant lorsque le tableau est déjà trié - dans ce cas, cela peut être fait sur place en temps O (n).
David Airapetyan

@ Vitim.us Non. Dans mon cas, ce n'est même pas un tableau, mais une liste <chaîne>. J'accepte toute réponse qui fait l'affaire. C'est peut-être un choc de devoir le faire sur papier.
AngryHacker

Réponses:


427

Vous pouvez éventuellement utiliser une requête LINQ pour ce faire:

int[] s = { 1, 2, 3, 3, 4};
int[] q = s.Distinct().ToArray();

22
Notez que vous pouvez utiliser un IEqualityComparer comme paramètre, par exemple .Distinct(StringComparer.OrdinalIgnoreCase)pour obtenir un ensemble de chaînes distinct insensible à la casse.
justisb

Distinct honore-t-il l'ordre d'origine des éléments?
asyrov

@asyrov: de MSDN:The Distinct() method returns an unordered sequence that contains no duplicate values.
tigrou

52

Voici l' approche HashSet <string> :

public static string[] RemoveDuplicates(string[] s)
{
    HashSet<string> set = new HashSet<string>(s);
    string[] result = new string[set.Count];
    set.CopyTo(result);
    return result;
}

Malheureusement, cette solution nécessite également .NET Framework 3.5 ou version ultérieure, car HashSet n'a pas été ajouté avant cette version. Vous pouvez également utiliser array.Distinct () , qui est une fonctionnalité de LINQ.


11
Cela ne préservera probablement pas la commande d'origine.
Hamish Grubijan

11

Le code testé et fonctionnel suivant supprimera les doublons d'un tableau. Vous devez inclure l'espace de noms System.Collections.

string[] sArray = {"a", "b", "b", "c", "c", "d", "e", "f", "f"};
var sList = new ArrayList();

for (int i = 0; i < sArray.Length; i++) {
    if (sList.Contains(sArray[i]) == false) {
        sList.Add(sArray[i]);
    }
}

var sNew = sList.ToArray();

for (int i = 0; i < sNew.Length; i++) {
    Console.Write(sNew[i]);
}

Vous pouvez envelopper cela dans une fonction si vous le souhaitez.


Cela semble être O (N ^ 2) ... Vous pouvez utiliser un tas au lieu d'une liste de tableaux
Neil Chowdhury

10

Si vous aviez besoin de le trier, vous pouvez implémenter un tri qui supprime également les doublons.

Tue deux oiseaux avec une pierre, alors.


7
Comment le tri supprime-t-il les doublons?
dan1

2
Qui a voté pour cela? Ce n'est pas une réponse. "Comment puis-je faire des crêpes?" "Mettez quelques ingrédients dans un arc et mélangez."
Quarkly

9

Cela peut dépendre de la quantité d'ingénierie que vous souhaitez concevoir - si le tableau ne sera jamais aussi grand et que vous ne vous souciez pas de trier la liste, vous voudrez peut-être essayer quelque chose de similaire à ce qui suit:

    public string[] RemoveDuplicates(string[] myList) {
        System.Collections.ArrayList newList = new System.Collections.ArrayList();

        foreach (string str in myList)
            if (!newList.Contains(str))
                newList.Add(str);
        return (string[])newList.ToArray(typeof(string));
    }

4
Vous devez utiliser List au lieu de ArrayList.
Doug S

7

- C'est une question d'entrevue posée à chaque fois. Maintenant, j'ai fait son codage.

static void Main(string[] args)
{    
            int[] array = new int[] { 4, 8, 4, 1, 1, 4, 8 };            
            int numDups = 0, prevIndex = 0;

            for (int i = 0; i < array.Length; i++)
            {
                bool foundDup = false;
                for (int j = 0; j < i; j++)
                {
                    if (array[i] == array[j])
                    {
                        foundDup = true;
                        numDups++; // Increment means Count for Duplicate found in array.
                        break;
                    }                    
                }

                if (foundDup == false)
                {
                    array[prevIndex] = array[i];
                    prevIndex++;
                }
            }

            // Just Duplicate records replce by zero.
            for (int k = 1; k <= numDups; k++)
            {               
                array[array.Length - k] = '\0';             
            }


            Console.WriteLine("Console program for Remove duplicates from array.");
            Console.Read();
        }

3
Vous ne devriez pas faire une complexité de temps O (n * 2) pour cette question.
dan1

2
Vous devez utiliser le tri par fusion
Nick Gallimore

7
List<String> myStringList = new List<string>();
foreach (string s in myStringArray)
{
    if (!myStringList.Contains(s))
    {
        myStringList.Add(s);
    }
}

Il s'agit de O (n ^ 2) , qui n'aura pas d'importance pour une courte liste qui sera insérée dans un combo, mais qui pourrait rapidement devenir un problème sur une grande collection.


6
protected void Page_Load(object sender, EventArgs e)
{
    string a = "a;b;c;d;e;v";
    string[] b = a.Split(';');
    string[] c = b.Distinct().ToArray();

    if (b.Length != c.Length)
    {
        for (int i = 0; i < b.Length; i++)
        {
            try
            {
                if (b[i].ToString() != c[i].ToString())
                {
                    Response.Write("Found duplicate " + b[i].ToString());
                    return;
                }
            }
            catch (Exception ex)
            {
                Response.Write("Found duplicate " + b[i].ToString());
                return;
            }
        }              
    }
    else
    {
        Response.Write("No duplicate ");
    }
}

6

Voici une approche O (n * n) qui utilise l' espace O (1) .

void removeDuplicates(char* strIn)
{
    int numDups = 0, prevIndex = 0;
    if(NULL != strIn && *strIn != '\0')
    {
        int len = strlen(strIn);
        for(int i = 0; i < len; i++)
        {
            bool foundDup = false;
            for(int j = 0; j < i; j++)
            {
                if(strIn[j] == strIn[i])
                {
                    foundDup = true;
                    numDups++;
                    break;
                }
            }

            if(foundDup == false)
            {
                strIn[prevIndex] = strIn[i];
                prevIndex++;
            }
        }

        strIn[len-numDups] = '\0';
    }
}

Les approches de hachage / linq ci-dessus sont celles que vous utiliseriez généralement dans la vie réelle. Cependant, dans les entretiens, ils veulent généralement mettre certaines contraintes, par exemple un espace constant qui exclut le hachage ou pas d' api interne - qui exclut l'utilisation de LINQ .


1
Comment peut-il utiliser l'espace O (1), alors que vous devez stocker la liste entière? En commençant par un tri in situ, vous pouvez faire du temps O (nlogn) et de la mémoire O (n), avec beaucoup moins de code.
Thomas Ahle

1
Qu'est-ce qui vous fait penser qu'il stocke la liste entière? Cela se fait en effet sur place. Et bien que ce ne soit pas une condition dans la question, mon code maintient l'ordre des caractères dans la chaîne d'origine. Le tri supprimera cela.
Sesh

1
La boucle interne ( strIn[j] == strIn[i]) comparera une chaîne à elle-même, sauf si elle est prise en compte avec une instruction if.
User3219

5

Ajoutez toutes les chaînes à un dictionnaire et obtenez ensuite la propriété Keys. Cela produira chaque chaîne unique, mais pas nécessairement dans le même ordre que votre entrée d'origine les avait.

Si vous souhaitez que le résultat final ait le même ordre que l'entrée d'origine, lorsque vous considérez la première occurrence de chaque chaîne, utilisez plutôt l'algorithme suivant:

  1. Avoir une liste (sortie finale) et un dictionnaire (pour vérifier les doublons)
  2. Pour chaque chaîne dans l'entrée, vérifiez si elle existe déjà dans le dictionnaire
  3. Sinon, ajoutez-le à la fois au dictionnaire et à la liste

À la fin, la liste contient la première occurrence de chaque chaîne unique.

Assurez-vous de prendre en compte des choses comme la culture et autres lors de la construction de votre dictionnaire, pour vous assurer de gérer correctement les doublons avec des lettres accentuées.


5

Le morceau de code suivant tente de supprimer les doublons d'une liste de tableaux bien que ce ne soit pas une solution optimale. On m'a posé cette question lors d'une interview pour supprimer les doublons par récursivité, et sans utiliser un second / temp arraylist:

private void RemoveDuplicate() 
{

ArrayList dataArray = new ArrayList(5);

            dataArray.Add("1");
            dataArray.Add("1");
            dataArray.Add("6");
            dataArray.Add("6");
            dataArray.Add("6");
            dataArray.Add("3");
            dataArray.Add("6");
            dataArray.Add("4");
            dataArray.Add("5");
            dataArray.Add("4");
            dataArray.Add("1");

            dataArray.Sort();

            GetDistinctArrayList(dataArray, 0);
}

private void GetDistinctArrayList(ArrayList arr, int idx)

{

            int count = 0;

            if (idx >= arr.Count) return;

            string val = arr[idx].ToString();
            foreach (String s in arr)
            {
                if (s.Equals(arr[idx]))
                {
                    count++;
                }
            }

            if (count > 1)
            {
                arr.Remove(val);
                GetDistinctArrayList(arr, idx);
            }
            else
            {
                idx += 1;
                GetDistinctArrayList(arr, idx);
            }
        }

5

Solution simple:

using System.Linq;
...

public static int[] Distinct(int[] handles)
{
    return handles.ToList().Distinct().ToArray();
}

5

Peut-être un hachage qui ne stocke pas les éléments en double et ignore silencieusement les demandes d'ajout de doublons.

static void Main()
{
    string textWithDuplicates = "aaabbcccggg";     

    Console.WriteLine(textWithDuplicates.Count());  
    var letters = new HashSet<char>(textWithDuplicates);
    Console.WriteLine(letters.Count());

    foreach (char c in letters) Console.Write(c);
    Console.WriteLine("");

    int[] array = new int[] { 12, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2 };

    Console.WriteLine(array.Count());
    var distinctArray = new HashSet<int>(array);
    Console.WriteLine(distinctArray.Count());

    foreach (int i in distinctArray) Console.Write(i + ",");
}

4

REMARQUE: NON testé!

string[] test(string[] myStringArray)
{
    List<String> myStringList = new List<string>();
    foreach (string s in myStringArray)
    {
        if (!myStringList.Contains(s))
        {
            myStringList.Add(s);
        }
    }
    return myStringList.ToString();
}

Pourrait faire ce dont vous avez besoin ...

EDIT Argh !!! battu par vol de moins d'une minute!


Rob ne vous a battu à rien. Il utilise ArrayList, pendant que vous utilisez List. Votre version est meilleure.
Doug S

4

Testé ci-dessous et cela fonctionne. Ce qui est cool, c'est qu'il fait aussi une recherche sensible à la culture

class RemoveDuplicatesInString
{
    public static String RemoveDups(String origString)
    {
        String outString = null;
        int readIndex = 0;
        CompareInfo ci = CultureInfo.CurrentCulture.CompareInfo;


        if(String.IsNullOrEmpty(origString))
        {
            return outString;
        }

        foreach (var ch in origString)
        {
            if (readIndex == 0)
            {
                outString = String.Concat(ch);
                readIndex++;
                continue;
            }

            if (ci.IndexOf(origString, ch.ToString().ToLower(), 0, readIndex) == -1)
            {
                //Unique char as this char wasn't found earlier.
                outString = String.Concat(outString, ch);                   
            }

            readIndex++;

        }


        return outString;
    }


    static void Main(string[] args)
    {
        String inputString = "aAbcefc";
        String outputString;

        outputString = RemoveDups(inputString);

        Console.WriteLine(outputString);
    }

}

--AptSenSDET


4

Ce code supprime à 100% les valeurs en double d'un tableau [comme j'ai utilisé un [i]] ..... Vous pouvez le convertir dans n'importe quel langage OO ..... :)

for(int i=0;i<size;i++)
{
    for(int j=i+1;j<size;j++)
    {
        if(a[i] == a[j])
        {
            for(int k=j;k<size;k++)
            {
                 a[k]=a[k+1];
            }
            j--;
            size--;
        }
    }

}

4

Méthode d'extension générique:

public static IEnumerable<TSource> Distinct<TSource>(this IEnumerable<TSource> source, IEqualityComparer<TSource> comparer)
{
    if (source == null)
        throw new ArgumentNullException(nameof(source));

    HashSet<TSource> set = new HashSet<TSource>(comparer);
    foreach (TSource item in source)
    {
        if (set.Add(item))
        {
            yield return item;
        }
    }
}

1

vous pouvez utiliser ce code lorsque vous travaillez avec une liste de tableaux

ArrayList arrayList;
//Add some Members :)
arrayList.Add("ali");
arrayList.Add("hadi");
arrayList.Add("ali");

//Remove duplicates from array
  for (int i = 0; i < arrayList.Count; i++)
    {
       for (int j = i + 1; j < arrayList.Count ; j++)
           if (arrayList[i].ToString() == arrayList[j].ToString())
                 arrayList.Remove(arrayList[j]);

1
public static int RemoveDuplicates(ref int[] array)
{
    int size = array.Length;

    // if 0 or 1, return 0 or 1:
    if (size  < 2) {
        return size;
    }

    int current = 0;
    for (int candidate = 1; candidate < size; ++candidate) {
        if (array[current] != array[candidate]) {
            array[++current] = array[candidate];
        }
    }

    // index to count conversion:
    return ++current;
}

0

Vous trouverez ci-dessous une logique simple en java: vous parcourez deux fois les éléments du tableau et si vous voyez un même élément, vous lui attribuez zéro et vous ne touchez pas l'index de l'élément que vous comparez.

import java.util.*;
class removeDuplicate{
int [] y ;

public removeDuplicate(int[] array){
    y=array;

    for(int b=0;b<y.length;b++){
        int temp = y[b];
        for(int v=0;v<y.length;v++){
            if( b!=v && temp==y[v]){
                y[v]=0;
            }
        }
    }
}

0
  private static string[] distinct(string[] inputArray)
        {
            bool alreadyExists;
            string[] outputArray = new string[] {};

            for (int i = 0; i < inputArray.Length; i++)
            {
                alreadyExists = false;
                for (int j = 0; j < outputArray.Length; j++)
                {
                    if (inputArray[i] == outputArray[j])
                        alreadyExists = true;
                }
                        if (alreadyExists==false)
                        {
                            Array.Resize<string>(ref outputArray, outputArray.Length + 1);
                            outputArray[outputArray.Length-1] = inputArray[i];
                        }
            }
            return outputArray;
        }

1
expliquez votre réponse, s'il vous plaît.
Badiparmagi

0
using System;
using System.Collections.Generic;
using System.Linq;


namespace Rextester
{
    public class Program
    {
        public static void Main(string[] args)
        {
             List<int> listofint1 = new List<int> { 4, 8, 4, 1, 1, 4, 8 };
           List<int> updatedlist= removeduplicate(listofint1);
            foreach(int num in updatedlist)
               Console.WriteLine(num);
        }


        public static List<int> removeduplicate(List<int> listofint)
         {
             List<int> listofintwithoutduplicate= new List<int>();


              foreach(var num in listofint)
                 {
                  if(!listofintwithoutduplicate.Any(p=>p==num))
                        {
                          listofintwithoutduplicate.Add(num);
                        }
                  }
             return listofintwithoutduplicate;
         }
    }



}

C'est une façon très inefficace de procéder. Jetez un œil aux autres réponses pour voir ce qu'elles font.
Wai Ha Lee

0
strINvalues = "1,1,2,2,3,3,4,4";
strINvalues = string.Join(",", strINvalues .Split(',').Distinct().ToArray());
Debug.Writeline(strINvalues);

Kkk Je ne sais pas si c'est de la sorcellerie ou tout simplement du beau code

1 strINvalues ​​.Split (','). Distinct (). ToArray ()

2 string.Join (",", XXX);

1 Fractionnement de la baie et utilisation de Distinct [LINQ] pour supprimer les doublons. 2 Rebranchez-la sans les doublons.

Désolé je n'ai jamais lu le texte sur StackOverFlow juste le code. cela a plus de sens que le texte;)


Les réponses uniquement codées sont des réponses de faible qualité. Ajoutez quelques explications pour expliquer pourquoi cela fonctionne.
Taslim Oseni

0
int size = a.Length;
        for (int i = 0; i < size; i++)
        {
            for (int j = i + 1; j < size; j++)
            {
                if (a[i] == a[j])
                {
                    for (int k = j; k < size; k++)
                    {
                        if (k != size - 1)
                        {
                            int temp = a[k];
                            a[k] = a[k + 1];
                            a[k + 1] = temp;

                        }
                    }
                    j--;
                    size--;
                }
            }
        }

1
Bienvenue chez SO. Bien que cet extrait de code puisse être la solution, y compris une explication aide vraiment à améliorer la qualité de votre message. N'oubliez pas que vous répondrez à la question des lecteurs à l'avenir et que ces personnes ne connaissent peut-être pas les raisons de votre suggestion de code.
alan.elkin

Malheureusement, ce code ne supprime rien, il ne supprime donc pas les doublons.
P_P

0

Le meilleur moyen? Difficile à dire, l'approche HashSet semble rapide, mais (selon les données) l'utilisation d'un algorithme de tri (CountSort?) Peut être beaucoup plus rapide.

using System;
using System.Collections.Generic;
using System.Linq;
class Program
{
    static void Main()
    {
        Random r = new Random(0); int[] a, b = new int[1000000];
        for (int i = b.Length - 1; i >= 0; i--) b[i] = r.Next(b.Length);
        a = new int[b.Length]; Array.Copy(b, a, b.Length);
        a = dedup0(a); Console.WriteLine(a.Length);
        a = new int[b.Length]; Array.Copy(b, a, b.Length);
        var w = System.Diagnostics.Stopwatch.StartNew();
        a = dedup0(a); Console.WriteLine(w.Elapsed); Console.Read();
    }

    static int[] dedup0(int[] a)  // 48 ms  
    {
        return new HashSet<int>(a).ToArray();
    }

    static int[] dedup1(int[] a)  // 68 ms
    {
        Array.Sort(a); int i = 0, j = 1, k = a.Length; if (k < 2) return a;
        while (j < k) if (a[i] == a[j]) j++; else a[++i] = a[j++];
        Array.Resize(ref a, i + 1); return a;
    }

    static int[] dedup2(int[] a)  //  8 ms
    {
        var b = new byte[a.Length]; int c = 0;
        for (int i = 0; i < a.Length; i++) 
            if (b[a[i]] == 0) { b[a[i]] = 1; c++; }
        a = new int[c];
        for (int j = 0, i = 0; i < b.Length; i++) if (b[i] > 0) a[j++] = i;
        return a;
    }
}

Presque sans branche. Comment? Mode de débogage, Step Into (F11) avec un petit tableau: {1,3,1,1,0}

    static int[] dedupf(int[] a)  //  4 ms
    {
        if (a.Length < 2) return a;
        var b = new byte[a.Length]; int c = 0, bi, ai, i, j;
        for (i = 0; i < a.Length; i++)
        { ai = a[i]; bi = 1 ^ b[ai]; b[ai] |= (byte)bi; c += bi; }
        a = new int[c]; i = 0; while (b[i] == 0) i++; a[0] = i++;
        for (j = 0; i < b.Length; i++) a[j += bi = b[i]] += bi * i; return a;
    }

Une solution avec deux boucles imbriquées peut prendre un certain temps, en particulier pour les baies plus grandes.

    static int[] dedup(int[] a)
    {
        int i, j, k = a.Length - 1;
        for (i = 0; i < k; i++)
            for (j = i + 1; j <= k; j++) if (a[i] == a[j]) a[j--] = a[k--];
        Array.Resize(ref a, k + 1); return a;
    }
En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.