Как удалить дубликаты из массива C#?

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

Как лучше всего удалить дубликаты из массива C#?

В самом деле. Еще интереснее, когда массив уже отсортирован - в этом случае это можно сделать на месте за время O (n).

David Airapetyan 03.03.2012 00:54

@ Vitim.us Нет. В моем случае это даже не массив, а List. Я принимаю любой ответ, который работает. Возможно, это шок от того, что это нужно делать на бумаге.

AngryHacker 23.11.2012 04:05

Используйте метод расширения Distinct.

kokos 13.08.2008 16:02
Стоит ли изучать PHP в 2026-2027 годах?
Стоит ли изучать PHP в 2026-2027 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
221
3
337 830
27
Перейти к ответу Данный вопрос помечен как решенный

Ответы 27

Если вам нужно отсортировать его, вы можете реализовать сортировку, которая также удаляет дубликаты.

Значит, убивает двух зайцев одним выстрелом.

Как сортировка удаляет дубликаты?

dan1 18.05.2016 03:46

Кто проголосовал за это? Это не ответ. "Как мне приготовить блины?" «Положите ингредиенты в лук и перемешайте».

Quarkly 04.04.2020 22:21

Верно, это действительно не ответ. Думаю, это был комментарий, сделанный до комментариев StackOverflow имел. Этот вопрос задавали, когда на SO было меньше 10 тысяч вопросов.

Matthew Schinckel 20.08.2020 07:13
Ответ принят как подходящий

Для этого вы могли бы использовать запрос LINQ:

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

Обратите внимание, что вы можете использовать IEqualityComparer в качестве параметра, например .Distinct(StringComparer.OrdinalIgnoreCase), чтобы получить отдельный набор строк без учета регистра.

justisb 13.10.2015 19:26

Учитывает ли Distinct исходный порядок элементов?

asyrov 25.02.2017 01:35

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

tigrou 03.10.2018 13:13

Добавьте все строки в словарь, а затем получите свойство Keys. Это создаст каждую уникальную строку, но не обязательно в том же порядке, в котором они были в исходном вводе.

Если вам требуется, чтобы конечный результат имел тот же порядок, что и исходный ввод, при рассмотрении первого появления каждой строки вместо этого используйте следующий алгоритм:

  1. Имейте список (окончательный результат) и словарь (для проверки дубликатов)
  2. Для каждой строки во входных данных проверьте, существует ли она уже в словаре
  3. Если нет, добавьте его как в словарь, так и в список.

В конце список содержит первое появление каждой уникальной строки.

Убедитесь, что вы учитываете такие вещи, как культура и тому подобное, когда составляете свой словарь, чтобы убедиться, что вы правильно обрабатываете дубликаты с акцентированными буквами.

Следующий протестированный и рабочий код удалит дубликаты из массива. Вы должны включить пространство имен 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

Neil 08.03.2019 23:47

Это может зависеть от того, насколько вы хотите разработать решение - если массив никогда не будет таким большим и вам не нужно сортировать список, вы можете попробовать что-то подобное следующему:

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

Вы должны использовать List вместо ArrayList.

Doug S 27.10.2012 09:05

ПРИМЕЧАНИЕ: НЕ проверено!

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

Сделай то, что тебе нужно ...

РЕДАКТИРОВАТЬ Ага !!! избит грабителем менее чем за минуту!

Роб тебя ни в чем не бил. Он использует ArrayList, а вы используете List. Ваша версия лучше.

Doug S 27.10.2012 09:05

Here is the 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.

Это, вероятно, не сохранит первоначальный порядок.

Hamish Grubijan 05.07.2011 19:07

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

Это О (п ^ 2), который не имеет значения для короткого списка, который будет объединен в комбо, но может быстро стать проблемой для большой коллекции.

Вот подход О (п * п), который использует пространство О (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 - это то, что вы обычно используете в реальной жизни. Однако на собеседовании обычно ставят некоторые ограничения, например: постоянное пространство, которое исключает хэш или отсутствие внутреннего api - что исключает использование LINQ.

Как он может использовать пространство O (1), когда вам нужно хранить весь список? Начав с сортировки на месте, вы можете сделать O (nlogn) времени и O (n) памяти с гораздо меньшим количеством кода.

Thomas Ahle 27.04.2010 09:19

Что заставляет вас думать, что он хранит весь список? Это действительно работает на месте. И хотя это не условие в вопросе, мой код поддерживает порядок символов в исходной строке. Сортировка удалит это.

Sesh 30.04.2010 10:10

Внутренний цикл (strIn[j] == strIn[i]) будет сравнивать строку с самой собой, если это не учитывается с помощью оператора if.

User3219 22.10.2018 22:46

Следующий фрагмент кода пытается удалить дубликаты из ArrayList, хотя это не оптимальное решение. Мне задали этот вопрос во время собеседования, чтобы удалить дубликаты с помощью рекурсии и без использования второго / временного arrayylist:

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

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

Может быть, 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 + ",");
}

Протестировано ниже, и оно работает. Что круто, так это то, что он также выполняет поиск с учетом культуры

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

- Это Вопрос на собеседовании спрашивают каждый раз. Теперь я его кодировал.

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

Вы не должны использовать временную сложность O (n * 2) для этого вопроса.

dan1 18.05.2016 03:50

Вы должны использовать сортировку слиянием

Nick Gallimore 13.06.2017 18:20

Этот код на 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--;
        }
    }

}

Простое решение:

using System.Linq;
...

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

вы можете использовать этот код при работе с 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]);

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

Ниже приведена простая логика в 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;
            }
        }
    }
}

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

объясните свой ответ, пожалуйста.

Badiparmagi 30.11.2017 11:10

Универсальный метод расширения:

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

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



}

Это очень неэффективный способ сделать это. Посмотрите другие ответы, чтобы узнать, что они делают.

Wai Ha Lee 25.04.2019 20:55

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 string.Join (",", XXX);

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

Извините, я никогда не читал текст на StackOverFlow, только код. в нем больше смысла, чем в тексте;)

Ответы, состоящие только из кода, являются ответами низкого качества. Добавьте объяснение, почему это работает.

Taslim Oseni 03.10.2019 22:07

Лучший путь? Трудно сказать, подход 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;
    }

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

Добро пожаловать в SO. Хотя этот фрагмент кода может быть решением, включение объяснения действительно помогает улучшить качество вашего сообщения. Помните, что вы отвечаете на вопрос для читателей в будущем, и эти люди могут не знать причины вашего предложения кода.

alan.elkin 07.06.2020 03:49

К сожалению, этот код ничего не удаляет, поэтому не удаляет дубликаты.

P_P 13.06.2020 11:43

Удаление дубликатов и игнорирование чувствительности к регистру с помощью Distinct и StringComparer.InvariantCultureIgnoreCase

string[] array = new string[] { "A", "a", "b", "B", "a", "C", "c", "C", "A", "1" };
var r = array.Distinct(StringComparer.InvariantCultureIgnoreCase).ToList();
Console.WriteLine(r.Count); // return 4 items

Найдите ответ ниже.

class Program
{
    static void Main(string[] args)
    {
        var nums = new int[] { 1, 4, 3, 3, 3, 5, 5, 7, 7, 7, 7, 9, 9, 9 };
        var result = removeDuplicates(nums);
        foreach (var item in result)
        {
            Console.WriteLine(item);
        }
    }
    static int[] removeDuplicates(int[] nums)
    {
        nums = nums.ToList().OrderBy(c => c).ToArray();
        int j = 1;
        int i = 0;
        int stop = 0;
        while (j < nums.Length)
        {
            if (nums[i] != nums[j])
            {
                nums[i + 1] = nums[j];
                stop = i + 2;
                i++;
            }
            j++;
        }
        nums = nums.Take(stop).ToArray();
        return nums;
    }
}

Небольшой вклад, основанный на тесте, который я только что решил, может быть полезным и открытым для улучшения другими ведущими участниками здесь. Вот что я сделал:

  1. Я использовал OrderBy, который позволяет мне упорядочивать или сортировать элементы от самых маленьких до самых высоких с помощью LINQ.
  2. Затем я конвертирую его обратно в массив, а затем повторно назначаю его основному источнику данных.
  3. Итак, я затем инициализирую j, которая является моей правой стороной массива, равной 1 и i, которая является моей левой стороной массива, равной 0, я также инициализирую, где я бы остановился, чтобы быть равным 0.
  4. Я использовал цикл while для увеличения по массиву, переходя от одной позиции к другой слева направо, для каждого приращения позиция остановки - это текущее значение i + 2, которое я буду использовать позже, чтобы вырезать дубликаты из массива.
  5. Затем я увеличиваю, перемещаясь слева направо от оператора if и справа направо за пределами оператора if, пока я не перейду через все значения массива.
  6. Затем я выбираю от первого элемента до позиции остановки, которая становится последним индексом i плюс 2. Таким образом я могу удалить все повторяющиеся элементы из массива int. который затем переназначается.

Другие вопросы по теме