Як видалити дублікати з масиву C #?


209

Я працюю з string[]масивом в C #, який повертається з виклику функції. Я, можливо, міг би подати аGeneric колекцію, але мені було цікаво, чи є кращий спосіб зробити це, можливо, використовуючи тимчасовий масив.

Який найкращий спосіб видалити дублікати з масиву C #?


4
Використовуйте метод розширення розрізнення.
кокос

Справді. Приємніше, коли масив вже відсортований - у такому випадку це можна зробити на місці за O (n) час.
Давид Айрапетян

@ Vitim.us Nope. У моєму випадку це навіть не масив, а Список <string>. Я приймаю будь-яку відповідь, яка робить роботу. Можливо, це шок, коли це потрібно робити на папері.
AngryHacker

Відповіді:


427

Ви можете використати запит LINQ для цього:

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

22
Зауважте, що ви можете використовувати IEqualityComparer як параметр, наприклад, .Distinct(StringComparer.OrdinalIgnoreCase)щоб отримати відмінний від регістру набір рядків.
justisb

Чи відрізняється відмінне відзначення оригінальним порядком елементів?
асиров

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

52

Ось підхід <string> HashSet :

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

На жаль, це рішення також вимагає .NET Framework 3.5 або пізнішої версії, оскільки HashSet не додано до цієї версії. Ви також можете використовувати array.Distinct () , що є особливістю LINQ.


11
Це, ймовірно, не збереже початковий порядок.
Гаміш Грубіян

11

Наступний перевірений і робочий код видалить дублікати з масиву. Ви повинні включити простір імен 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]);
}

Ви можете перетворити це на функцію, якщо хочете.


Здається, це O (N ^ 2) ... Ви можете використовувати купу замість ArrayList
Ніл

10

Якщо вам потрібно було відсортувати, ви можете реалізувати сортування, яке також видаляє дублікати.

Тоді вбиваємо двох птахів одним каменем.


7
Як сортування видаляє дублікати?
dan1

2
Хто проголосував за це? Це не відповідь. "Як зробити млинці?" "Покладіть деякі інгредієнти в лук і перемішайте".
Quarkly

9

Це може залежати від того, наскільки ви хочете розробляти рішення - якщо масив ніколи не буде таким великим, і вам не байдуже сортування списку, ви можете спробувати щось подібне до наступного:

    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
Ви повинні використовувати List замість ArrayList.
Doug S

7

- Це питання про інтерв'ю, яке задають кожен раз. Тепер я зробив його кодування.

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
Ви не повинні робити складну часову складність для цього питання.
dan1

2
Вам слід скористатися сортом злиття
Nick Gallimore

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

Це O (n ^ 2) , що не має значення для короткого списку, який буде вставлений у комбо, але це може бути проблемою для великої колекції.


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

Ось підхід O (n * n), який використовує простір 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';
    }
}

Наведені вище підходи до хеш-лінку - це те, що ви зазвичай використовуєте в реальному житті. Однак в інтерв'ю вони, як правило, хочуть поставити деякі обмеження, наприклад, постійний простір, який виключає хеш або відсутність внутрішніх інтерфейсів - які виключає використання LINQ .


1
Як він коли-небудь може використовувати пробіл O (1), коли потрібно зберігати весь список? Починаючи з inplace сортування, ви можете робити O (nlogn) час і O (n) пам'ять, з набагато меншим кодом.
Томас Ейл

1
Чому ви думаєте, що він зберігає весь список? Це дійсно робиться на місці. І хоча це не є умовою у питанні, мій код підтримує порядок символів у вихідному рядку. Сортування вилучить це.
Сеш

1
Внутрішній цикл ( strIn[j] == strIn[i]) буде порівнювати рядок із самим собою, якщо його не враховувати оператор if.
User3219

5

Додайте всі рядки до словника і отримайте властивість Keys після цього. Це призведе до створення кожного унікального рядка, але не обов'язково в тому ж порядку, в якому був у вашому оригінальному введенні.

Якщо вам потрібно, щоб кінцевий результат був таким самим, як вихідний вхід, коли ви враховуєте перше значення кожного рядка, замість цього використовуйте наступний алгоритм:

  1. Майте список (кінцевий вихід) та словник (щоб перевірити наявність дублікатів)
  2. Для кожного рядка на вході перевірте, чи він уже є у словнику
  3. Якщо ні, додайте його і до словника, і до списку

Наприкінці список містить першу кількість кожного унікального рядка.

Переконайтеся, що ви враховуєте такі речі, як культура та такі, коли створюєте словник, щоб переконатися, що ви правильно обробляєте дублікати з наголошеними літерами.


5

Наступний фрагмент коду намагається видалити дублікати з 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

Може бути хеш-набір, який не зберігає дублікати елементів і мовчки ігнорує запити на додавання дублікатів.

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

ПРИМІТКА: НЕ перевірено!

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

Ви можете зробити те, що вам потрібно ...

РЕДАКТУЙ Argh !!! побили його грабунком менше хвилини!


Роб не побив тебе ні до чого. Він використовує ArrayList, тоді як ви використовуєте List. Ваша версія краща.
Doug S

4

Протестовано нижче, і це працює. Приємно те, що він робить і культурно-чутливий пошук

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

Цей код на 100% видаляє повторювані значення з масиву [як я використовував [i]] ..... Ви можете конвертувати його в будь-яку мову 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

Загальний метод розширення:

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

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

Нижче наведена проста логіка в Java, ви двічі перетинаєте елементи масиву, і якщо ви бачите якийсь один і той же елемент, ви присвоюєте йому нуль плюс ви не торкаєтесь індексу елемента, який ви порівнюєте.

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
поясніть свою відповідь, будь ласка.
Бадіпармаги

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



}

Це дуже неефективний спосіб зробити це. Погляньте на інші відповіді, щоб побачити, що вони роблять.
Вай Ха Лі

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

Kkk Не впевнений, чи це чаклунство чи просто гарний код

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

2 рядок.Join (",", XXX);

1 Розщеплення масиву та використання Distinct [LINQ] для видалення дублікатів 2 Приєднання до нього назад без дублікатів.

Вибачте, що ніколи не читав текст на StackOverFlow лише код. це має більше сенсу, ніж текст;)


Відповіді, що містять код, - це відповіді низької якості. Додайте трохи пояснень, чому це працює.
Таслім Осені

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. Хоча цей фрагмент коду може бути вирішенням, включаючи пояснення, справді допомагає покращити якість вашої публікації. Пам’ятайте, що ви відповідаєте на запитання читачів у майбутньому, і ці люди можуть не знати причини вашої пропозиції щодо коду.
alan.elkin

На жаль, цей код нічого не видаляє, тому не видаляє дублікати.
P_P

0

Найкращий спосіб? Важко сказати, підхід HashSet виглядає швидко, але (залежно від даних) використання алгоритму сортування (CountSort?) Може бути набагато швидшим.

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

Майже відділення безкоштовно. Як? Режим налагодження: Крок у (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;
    }

Рішення з двома вкладеними петлями може зайняти деякий час, особливо для великих масивів.

    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;
    }
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.