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 #?

lomaxx
la source
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();
Jeff Atwood
la source
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.

Arcturus
la source
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.

GateKiller
la source
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.

Matthew Schinckel
la source
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));
    }
rjzii
la source
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();
        }
Muhammad Mubashir
la source
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.

Will Dean
la source
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 ");
    }
}
Pintu
la source
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 .

Sesh
la source
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.

Lasse V. Karlsen
la source
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);
            }
        }
Vijay Swami
la source
5

Solution simple:

using System.Linq;
...

public static int[] Distinct(int[] handles)
{
    return handles.ToList().Distinct().ToArray();
}
Fábio Delboni
la source
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 + ",");
}
lukaszk
la source
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!

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

AptSenSDET
la source
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--;
        }
    }

}
Salman Ramzan
la source
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;
        }
    }
}
Ali Bayat
la source
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]);
reza akhlaghi
la source
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;
}
Harry Martyrossian
la source
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;
            }
        }
    }
}
Papasani Mohansrinivas
la source
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;
        }
Arie Yehieli
la source
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;
         }
    }



}
Rohan
la source
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;)

Kudakwashe Mafutah
la source
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--;
                }
            }
        }
Swathi Sriramaneni
la source
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;
    }
P_P
la source