Bir C # dizisinden yinelenenleri nasıl kaldırabilirim?


209

string[]Bir işlev çağrısından döndürülür C # bir dizi ile çalışıyorum . Muhtemelen bir Generickoleksiyona dökülebilirdim , ama muhtemelen temp dizisini kullanarak bunu yapmanın daha iyi bir yolu olup olmadığını merak ediyordum.

Bir C # dizisinden yinelenenleri kaldırmanın en iyi yolu nedir?


4
Farklı uzantı yöntemini kullanın.
kokos

Aslında. Dizi zaten sıralandığında daha eğlencelidir - bu durumda O (n) zamanında yerinde yapılabilir.
David Airapetyan

@ Vitim.us Hayır. Benim durumumda, bu bir dizi değil, bir <string> Listesi. İşi yapan herhangi bir cevabı kabul ediyorum. Belki de bunu kağıt üzerinde yapmak zorunda kalmanın bir şoku.
AngryHacker

Yanıtlar:


427

Bunu yapmak için muhtemelen bir LINQ sorgusu kullanabilirsiniz:

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

22
Büyük / .Distinct(StringComparer.OrdinalIgnoreCase)küçük harf duyarsız farklı dizeler kümesi gibi bir IEqualityComparer parametresi kullanabileceğinizi unutmayın .
justisb

Farklı unsurların orijinal sırasını onurlandırıyor mu?
asyrov

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

52

İşte HashSet <string> yaklaşımı:

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

Ne yazık ki bu çözüm, HashSet bu sürüme kadar eklenmediğinden .NET framework 3.5 veya üstünü de gerektirir. LINQ'nun bir özelliği olan array.Distinct () öğesini de kullanabilirsiniz .


11
Bu muhtemelen orijinal siparişi korumaz.
Hamish Grubijan

11

Aşağıdaki test edilmiş ve çalışma kodu, bir diziden yinelenenleri kaldıracaktır. System.Collections ad alanını eklemeniz gerekir.

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

İsterseniz bunu bir işleve sarılabilirsiniz.


Bu O (N ^ 2) gibi görünüyor ... ArrayList yerine bir yığın kullanabilirsiniz
Neil Chowdhury

10

Sıralamanız gerekiyorsa, yinelenenleri de kaldıran bir sıralama uygulayabilirsiniz.

Öyleyse, bir taşla iki kuşu öldürür.


7
Sıralama, kopyaları nasıl kaldırır?
dan1

2
Buna kim oy verdi? Bu bir cevap değil. "Nasıl krep yaparım?" "Bazı malzemeleri bir pruvaya koy ve karıştır."
Quarkly

9

Bu, çözümü ne kadar mühendislik yapmak istediğinize bağlı olabilir - eğer dizi asla bu kadar büyük olmayacaksa ve listeyi sıralamayı umursamıyorsanız, aşağıdakine benzer bir şey denemek isteyebilirsiniz:

    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
ArrayList yerine List kullanmalısınız.
Doug S

7

- Bu her zaman sorulan Mülakat Sorusu . Şimdi kodlamasını yaptım.

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
Bu soru için O (n * 2) zaman karmaşıklığı yapmamalısınız.
dan1

2
Birleştirme sıralaması kullanmalısınız
Nick Gallimore

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

Bu O (n ^ 2) , bir komboya girecek kısa bir liste için önemli değil, ancak büyük bir koleksiyonda hızlı bir şekilde sorun olabilir.


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

İşte O (1) boşluğunu kullanan bir O (n * n) yaklaşımı .

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

Yukarıdaki karma / linq yaklaşımları genellikle gerçek hayatta kullanacağınız yaklaşımlardır. Ancak mülakatlarda genellikle bazı kısıtlamalar koymak isterler, örneğin LINQ kullanarak kural dışı bırakan ya da iç uygulama içermeyen sabit alan .


1
Tüm listeyi saklamanız gerektiğinde O (1) alanını nasıl kullanabilir? Bir yerinde sıralama ile başlayarak, çok daha az kodla O (nlogn) zaman ve O (n) bellek yapabilirsiniz.
Thomas Ahle

1
Listenin tamamını sakladığını düşündüren nedir? Gerçekten yerinde yapıyor. Ve sorudaki bir koşul olmasa da, kodum orijinal dizedeki karakterlerin sırasını korur. Sıralama bunu kaldıracaktır.
Nisan'da Sesh

1
İç döngü ( strIn[j] == strIn[i]), bir if ifadesiyle hesaba katılmadığı sürece bir dizeyi kendisiyle karşılaştırır.
Kullanıcı3219

5

Tüm dizeleri bir sözlüğe ekleyin ve daha sonra Keys özelliğini edinin. Bu, her benzersiz dizeyi üretir, ancak orijinal girdinizin bunlarla aynı sırada olması gerekmez.

Son sonucun orijinal girişle aynı sıraya sahip olmasını istiyorsanız, her bir dizenin ilk tekrarlamasını düşündüğünüzde, aşağıdaki algoritmayı kullanın:

  1. Bir liste (son çıktı) ve bir sözlük (kopyaları kontrol etmek için)
  2. Girişteki her dize için, sözlüğün zaten var olup olmadığını kontrol edin
  3. Değilse, hem sözlüğe hem de listeye ekleyin

Sonunda, liste her benzersiz dizgenin ilk oluşumunu içerir.

Sözlüğünüzü oluştururken kültür ve benzeri şeyleri düşündüğünüzden emin olun, yinelenen harfleri aksanlı harflerle doğru şekilde işlediğinizden emin olun.


5

Aşağıdaki kod parçası, bu en iyi çözüm olmasa da bir ArrayList'ten yinelenenleri kaldırmaya çalışır. Bir röportaj sırasında, yinelenenleri yineleme yoluyla ve ikinci / geçici bir arraylist kullanmadan kaldırmam için bu soru soruldu:

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

Basit çözüm:

using System.Linq;
...

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

5

Belki yinelenen öğeleri saklamayan ve yinelenenleri ekleme isteklerini sessizce yok sayan hashset.

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

NOT: Test EDİLMEDİ!

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

İhtiyacınız olanı yapabilir ...

DÜZENLE Düzenle !!! bir dakikadan az bir sürede soymak için dövüldü!


Rob seni hiçbir şeye vurmadı. List'i kullanırken ArrayList kullanıyor. Sürümünüz daha iyi.
Doug S

4

Aşağıdaki test ve çalışıyor. Güzel olan, kültüre duyarlı bir arama da yapması

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

Bu kod% 100 bir diziden yinelenen değerleri kaldırmak [bir [i] kullandığım gibi] ..... Herhangi bir OO dilinde dönüştürebilirsiniz ..... :)

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

Genel Uzantı yöntemi:

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

ArrayList ile çalışırken bu kodu kullanabilirsiniz

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

Aşağıda, basit bir mantık dizinin öğelerini iki kez geçersiniz ve aynı öğeyi görürseniz ona sıfır atarsınız, ayrıca karşılaştırdığınız öğenin dizinine dokunmazsınız.

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
Cevabınızı açıklayınız, lütfen.
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;
         }
    }



}

Bunu yapmanın çok verimsiz bir yoludur. Ne yaptıklarını görmek için diğer cevaplara bir göz atın.
Wai Ha Lee

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

Kkk Bu büyücülük mü yoksa sadece güzel kod mu olduğundan emin değilim

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

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

1 Diziyi bölme ve yinelemeleri kaldırmak için Distinct [LINQ] kullanma 2 tekrar birleştirme.

Üzgünüm ben sadece kod StackOverFlow metni asla. metinden daha mantıklıdır;)


Yalnızca kod yanıtları düşük kaliteli yanıtlardır. Bunun neden işe yaradığına dair biraz açıklama ekleyin.
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
SO hoş geldiniz. Bu kod snippet'i çözüm olsa da, bir açıklama da dahil olmak üzere mesajınızın kalitesini artırmaya yardımcı olur. Gelecekte okuyucular için soruyu cevapladığınızı ve bu kişilerin kod önerinizin nedenlerini bilmeyebileceğini unutmayın.
alan.elkin

Ne yazık ki bu kod hiçbir şeyi kaldırmaz, bu nedenle kopyaları kaldırmaz.
P_P

0

En iyi yol? Söylemesi zor, HashSet yaklaşımı hızlı görünüyor, ancak (verilere bağlı olarak) bir sıralama algoritması (CountSort?) Kullanarak çok daha hızlı olabilir.

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

Neredeyse şube ücretsiz. Nasıl? Hata ayıklama modu, Küçük bir diziyle Adım Adım (F11): {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;
    }

İki iç içe döngü içeren bir çözüm, özellikle daha büyük diziler için biraz zaman alabilir.

    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;
    }
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.