Jak usunąć duplikaty z tablicy C #?


209

Pracowałem z string[]tablicą w języku C #, która jest zwracana z wywołania funkcji. Mogłem ewentualnie przesyłać do Generickolekcji, ale zastanawiałem się, czy istnieje lepszy sposób, aby to zrobić, być może przy użyciu tablicy tymczasowej.

Jaki jest najlepszy sposób na usunięcie duplikatów z tablicy C #?


4
Użyj metody rozszerzenia Distinct.
kokos

W rzeczy samej. Więcej zabawy sprawia, że ​​tablica jest już posortowana - w takim przypadku można to zrobić na miejscu w czasie O (n).
David Airapetyan

@ Vitim.us Nope. W moim przypadku nie jest to nawet tablica, ale lista <ciąg>. Przyjmuję każdą odpowiedź, która działa. Być może to szok, że trzeba to zrobić na papierze.
AngryHacker

Odpowiedzi:


427

Aby to zrobić, możesz użyć zapytania LINQ:

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

22
Zauważ, że możesz użyć IEqualityComparer jako parametru, na przykład, .Distinct(StringComparer.OrdinalIgnoreCase)aby otrzymać rozróżniany bez rozróżniania wielkości liter zestaw ciągów.
justisb

Czy Distinct honoruje oryginalną kolejność elementów?
asyrov

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

52

Oto podejście HashSet <ciąg> :

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

Niestety to rozwiązanie wymaga również .NET Framework 3.5 lub nowszego, ponieważ HashSet został dodany dopiero w tej wersji. Możesz także użyć array.Distinct () , która jest funkcją LINQ.


11
To prawdopodobnie nie zachowa oryginalnego zamówienia.
Hamish Grubijan,

11

Poniższy przetestowany i działający kod usunie duplikaty z tablicy. Musisz dołączyć przestrzeń nazw 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]);
}

Możesz zawinąć to w funkcję, jeśli chcesz.


Wygląda na to, że to O (N ^ 2) ... Możesz użyć sterty zamiast ArrayList
Neil Chowdhury

10

Jeśli musisz to posortować, możesz zaimplementować sortowanie, które również usuwa duplikaty.

Zabija dwa ptaki jednym kamieniem.


7
W jaki sposób sortowanie usuwa duplikaty?
dan1

2
Kto to zagłosował? To nie jest odpowiedź. „Jak zrobić naleśniki?” „Połóż niektóre składniki w łuku i wymieszaj”.
Quarkly

9

Może to zależeć od tego, jak bardzo chcesz zaprojektować rozwiązanie - jeśli tablica nigdy nie będzie tak duża i nie obchodzi Cię sortowanie listy, możesz spróbować czegoś podobnego do następującego:

    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
Powinieneś użyć List zamiast ArrayList.
Doug S

7

- To pytanie do wywiadu zadawane za każdym razem. Teraz zrobiłem jego kodowanie.

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
Nie powinieneś robić złożoności czasowej O (n * 2) dla tego pytania.
dan1

2
Powinieneś użyć sortowania
korespondencji

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

To jest O (n ^ 2) , co nie będzie miało znaczenia dla krótkiej listy, która ma zostać upakowana w kombinację, ale może szybko stanowić problem w dużej kolekcji.


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

Oto podejście O (n * n), które wykorzystuje przestrzeń 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';
    }
}

Podejścia do hash / linq powyżej są tym, czego zwykle używasz w prawdziwym życiu. Jednak w wywiadach zwykle chcą nałożyć pewne ograniczenia, np. Stałą przestrzeń wykluczającą hasz lub brak wewnętrznego interfejsu API - co wyklucza użycie LINQ .


1
Jak w ogóle może korzystać z miejsca O (1), skoro musisz przechowywać całą listę? Zaczynając od sortowania na miejscu, możesz wykonywać czas O (nlogn) i pamięć O (n) przy znacznie mniejszym kodzie.
Thomas Ahle

1
Co sprawia, że ​​myślisz, że przechowuje całą listę? Rzeczywiście działa w miejscu. I choć nie jest to warunek w pytaniu, mój kod zachowuje porządek znaków w oryginalnym ciągu. Sortowanie to usunie.
Sesh

1
Wewnętrzna pętla ( strIn[j] == strIn[i]) będzie porównywała ciąg do siebie, chyba że zostanie uwzględniona instrukcja if.
User3219,

5

Dodaj wszystkie ciągi do słownika, a następnie uzyskaj właściwość Keys. Spowoduje to wygenerowanie każdego unikalnego ciągu, ale niekoniecznie w tej samej kolejności, w jakiej znajdowały się w nim oryginalne dane wejściowe.

Jeśli chcesz, aby wynik końcowy miał taką samą kolejność jak oryginalne dane wejściowe, rozważając pierwsze wystąpienie każdego łańcucha, zastosuj następujący algorytm:

  1. Mieć listę (wynik końcowy) i słownik (w celu sprawdzenia duplikatów)
  2. Dla każdego ciągu wejściowego sprawdź, czy już istnieje w słowniku
  3. Jeśli nie, dodaj go zarówno do słownika, jak i do listy

Na końcu lista zawiera pierwsze wystąpienie każdego unikalnego ciągu.

Upewnij się, że podczas konstruowania słownika bierzesz pod uwagę takie elementy, jak kultura, i upewnij się, że poprawnie obsługujesz duplikaty z literami akcentowanymi.


5

Poniższy fragment kodu próbuje usunąć duplikaty z ArrayList, choć nie jest to optymalne rozwiązanie. Zadano mi to pytanie podczas wywiadu w celu usunięcia duplikatów poprzez rekurencję i bez użycia tablicy drugiego / tymczasowego:

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

Proste rozwiązanie:

using System.Linq;
...

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

5

Może hashset, który nie przechowuje duplikatów elementów i po cichu ignoruje żądania dodania duplikatów.

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

UWAGA: NIE testowane!

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

Może zrobić to, czego potrzebujesz ...

EDYCJA Argh !!! pobity przez rob przez niecałą minutę!


Rob do niczego cię nie pobił. Używa ArrayList, podczas gdy ty używasz listy. Twoja wersja jest lepsza.
Doug S

4

Przetestowałem poniżej i działa. Fajne jest to, że przeprowadza wyszukiwanie wrażliwe na kulturę

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

Ten kod w 100% usuwa zduplikowane wartości z tablicy [jak użyłem [i]] ..... Możesz przekonwertować go na dowolny język 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

Ogólna metoda rozszerzenia:

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

możesz użyć tego kodu podczas pracy z ArrayList

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

Poniżej znajduje się prosta logika w java, w której dwukrotnie przemierzasz elementy tablicy, a jeśli widzisz ten sam element, przypisujesz mu zero, a także nie dotykasz indeksu elementu, który porównujesz.

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
proszę wyjaśnij swoją odpowiedź.
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;
         }
    }



}

Jest to bardzo nieefektywny sposób na zrobienie tego. Spójrz na inne odpowiedzi, aby zobaczyć, co robią.
Wai Ha Lee,

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

Kkk Nie jestem pewien, czy to czary, czy tylko piękny kod

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

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

1 Podział tablicy i użycie Distinct [LINQ] do usunięcia duplikatów 2 Ponowne połączenie z powrotem bez duplikatów.

Niestety, nigdy nie czytałem tekstu na StackOverFlow, tylko kod. ma to większy sens niż tekst;)


Odpowiedzi tylko kodowe są odpowiedziami niskiej jakości. Dodaj wyjaśnienie, dlaczego to działa.
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
Witamy w SO. Ten fragment kodu może być rozwiązaniem, ale wyjaśnienie naprawdę pomaga poprawić jakość posta. Pamiętaj, że w przyszłości odpowiadasz na pytanie dla czytelników, a ci ludzie mogą nie znać przyczyn Twojej sugestii kodu.
alan.elkin

Niestety ten kod niczego nie usuwa, więc nie usuwa duplikatów.
P_P

0

Najlepszym sposobem? Trudno powiedzieć, podejście HashSet wygląda szybko, ale (w zależności od danych) użycie algorytmu sortowania (CountSort?) Może być znacznie szybsze.

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

Prawie bez oddziałów. W jaki sposób? Tryb debugowania, krok do (F11) z małą tablicą: {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;
    }

Rozwiązanie z dwiema zagnieżdżonymi pętlami może zająć trochę czasu, szczególnie w przypadku większych tablic.

    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;
    }
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.