Удаление дубликатов из List <T> в C#

У кого-нибудь есть быстрый способ дедупликации общего списка на C#?

Вы заботитесь о порядке элементов в результате? Это исключит некоторые решения.

Colonel Panic 01.12.2017 12:25

Однострочное решение: ICollection<MyClass> withoutDuplicates = new HashSet<MyClass>(inputList);

Harald Coppoolse 13.03.2019 15:44
Стоит ли изучать 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 называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
527
2
632 066
27
Перейти к ответу Данный вопрос помечен как решенный

Ответы 27

Отсортируйте его, затем отметьте два и два рядом друг с другом, так как дубликаты будут слипаться.

Что-то вроде этого:

list.Sort();
Int32 index = list.Count - 1;
while (index > 0)
{
    if (list[index] == list[index - 1])
    {
        if (index < list.Count - 1)
            (list[index], list[list.Count - 1]) = (list[list.Count - 1], list[index]);
        list.RemoveAt(list.Count - 1);
        index--;
    }
    else
        index--;
}

Примечания:

  • Сравнение выполняется снизу вверх, чтобы не приходилось прибегать к списку вариантов после каждого удаления.
  • В этом примере теперь используются кортежи значений C# для обмена, замените их соответствующим кодом, если вы не можете его использовать.
  • Конечный результат больше не сортируется

Если я не ошибаюсь, большинство из упомянутых выше подходов - это просто абстракции именно этих подпрограмм, не так ли? Я бы воспользовался вашим подходом, Лассе, потому что это то, как я мысленно представляю движение через данные. Но теперь меня интересуют различия в производительности между некоторыми предложениями.

Ian Patrick Hughes 12.08.2009 00:52

Реализуйте их и рассчитайте время, только так можно быть уверенным. Даже нотация Big-O не поможет вам с фактическими показателями производительности, а только взаимосвязь эффекта роста.

Lasse V. Karlsen 12.08.2009 11:03

Мне нравится этот подход, он более переносим на другие языки.

Jerry Liang 14.05.2012 04:26

Не делай этого. Это очень медленно. RemoveAt - очень дорогостоящая операция на List.

Clément 10.02.2013 01:53

Клеман прав. Чтобы спасти это, можно было бы обернуть это в метод, который дает с перечислителем и возвращает только отдельные значения. В качестве альтернативы вы можете скопировать значения в новый массив или список.

JHubbard80 25.10.2013 21:08

это кажется связанным, обсуждает проблему медленного удаления в списке stackoverflow.com/questions/6926554/…

barlop 05.09.2016 18:10

Вместо использования RemoveAt вы должны заменить последнее значение в списке. Затем удалите последние предметы (уменьшив счет). Затем снова выполните сортировку.

darkgaze 28.05.2019 17:21

@darkgaze Я взял на себя смелость улучшить ваше предложение, запустив цикл сравнения от начала до конца, я мог избежать использования курорта в цикле.

Lasse V. Karlsen 29.05.2019 09:22

Однако в C# есть гораздо лучшие альтернативы, такие как отчет Distinct выше, поэтому я не думаю, что кто-то все равно будет использовать этот код.

Lasse V. Karlsen 29.05.2019 09:24

@ LasseVågsætherKarlsen Спасибо. Где вы его модифицировали? Я тоже написал ответ в этой ветке. stackoverflow.com/a/56344965/772739

darkgaze 30.05.2019 14:23
Ответ принят как подходящий

Возможно, вам стоит подумать об использовании HashSet.

Из ссылки MSDN:

using System;
using System.Collections.Generic;

class Program
{
    static void Main()
    {
        HashSet<int> evenNumbers = new HashSet<int>();
        HashSet<int> oddNumbers = new HashSet<int>();

        for (int i = 0; i < 5; i++)
        {
            // Populate numbers with just even numbers.
            evenNumbers.Add(i * 2);

            // Populate oddNumbers with just odd numbers.
            oddNumbers.Add((i * 2) + 1);
        }

        Console.Write("evenNumbers contains {0} elements: ", evenNumbers.Count);
        DisplaySet(evenNumbers);

        Console.Write("oddNumbers contains {0} elements: ", oddNumbers.Count);
        DisplaySet(oddNumbers);

        // Create a new HashSet populated with even numbers.
        HashSet<int> numbers = new HashSet<int>(evenNumbers);
        Console.WriteLine("numbers UnionWith oddNumbers...");
        numbers.UnionWith(oddNumbers);

        Console.Write("numbers contains {0} elements: ", numbers.Count);
        DisplaySet(numbers);
    }

    private static void DisplaySet(HashSet<int> set)
    {
        Console.Write("{");
        foreach (int i in set)
        {
            Console.Write(" {0}", i);
        }
        Console.WriteLine(" }");
    }
}

/* This example produces output similar to the following:
 * evenNumbers contains 5 elements: { 0 2 4 6 8 }
 * oddNumbers contains 5 elements: { 1 3 5 7 9 }
 * numbers UnionWith oddNumbers...
 * numbers contains 10 elements: { 0 2 4 6 8 1 3 5 7 9 }
 */

это невероятно быстро ... 100000 строк со списком занимают 400 с и 8 МБ оперативной памяти, мое собственное решение занимает 2,5 с и 28 МБ, hashset занимает 0,1 с !!! и 11 МБ оперативной памяти

sasjaq 26.03.2013 02:28

HashSetне имеет индекса, поэтому использовать его не всегда возможно. Мне нужно один раз создать огромный список без дубликатов, а затем использовать его для ListView в виртуальном режиме. Было очень быстро создать HashSet<>, а затем преобразовать его в List<> (чтобы ListView мог получить доступ к элементам по индексу). List<>.Contains() работает слишком медленно.

Sinatr 31.07.2013 12:50

Помогло бы, если бы был пример того, как использовать хэш-набор в этом конкретном контексте.

Nathan McKaskle 28.01.2015 20:04

Как это можно считать ответом? Это ссылка

mcont 04.06.2015 18:13

HashSet отлично подходит в большинстве случаев. Но если у вас есть такой объект, как DateTime, он сравнивается по ссылке, а не по значению, поэтому вы все равно получите дубликаты.

Jason McKindly 09.12.2015 23:03

Если кто-то еще захочет использовать HashSet <T> внутри шаблона T4, вам необходимо добавить явную ссылку на сборку System.Core: <# @ assembly name = "System.Core" #> <# @ import namespace = "System.Collections.Generic" #> (см. stackoverflow.com/questions/247005/…)

Cesar 09.01.2016 12:31

@sasjaq, почему бы вам не опубликовать свое решение, если оно такое хорошее и быстрое?

barlop 05.09.2016 17:58

@barlop мое решение в 150 раз быстрее, чем сам список, но в 25 раз медленнее, чем hashset ... кстати, мое решение состоит в том, чтобы разделить каждую строку на двухбуквенные ключи и создать древовидную структуру, где вы можете сравнить путь для каждой двухбуквенной полосы искомого термина .

sasjaq 06.09.2016 12:30

обратите внимание, что в linq Distinct используется Set<T>linksource.microsoft.com/#System.Core/System/Linq/…

pm100 09.02.2017 19:31

@JasonMcKindly: почему ты так думаешь? Ему просто нужно предоставить значимый Equals + GetHashCode (верно для DateTime). Даже если в типе его нет, вы можете использовать HashSet-конструктор, который принимает IEqualityComparer<T> в качестве аргумента.

Tim Schmelter 09.02.2017 19:32

HashSet не подходит, когда у вас очень мало элементов (300 вместо 10.000). Это НАМНОГО быстрее, используя список или, что еще лучше, массив, добавляйте нужные элементы, затем сортируйте их непосредственно перед тем, как они вам понадобятся, а затем удаляйте дубликаты. Даже делать все это вручную быстрее, чем использовать HashSet для очень небольшого количества элементов.

darkgaze 28.05.2019 17:19

В Java (я предполагаю, что C# более или менее идентичен):

list = new ArrayList<T>(new HashSet<T>(list))

Если вы действительно хотели изменить исходный список:

List<T> noDupes = new ArrayList<T>(new HashSet<T>(list));
list.clear();
list.addAll(noDupes);

Чтобы сохранить порядок, просто замените HashSet на LinkedHashSet.

в C# это будет: List <T> noDupes = new List <T> (new HashSet <T> (list)); list.Clear (); list.AddRange (noDupes);

smohamed 16.04.2012 18:45

В C# это проще: var noDupes = new HashSet<T>(list); list.Clear(); list.AddRange(noDupes); :)

nawfal 26.05.2014 15:20

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

var unique = new List<T>();
var hs = new HashSet<T>();
foreach (T t in list)
    if (hs.Add(t))
        unique.Add(t);

Или способ Linq:

var hs = new HashSet<T>();
list.All( x =>  hs.Add(x) );

Редактировать: Метод HashSet - это время O(N) и пространство O(N), в то время как сортировка и последующее создание уникальных (как предлагает @ лассевк и другие) - это время O(N*lgN) и пространство O(1), поэтому мне не так ясно (как это было на первый взгляд), что способ сортировки уступает (мои извинения за временное голосование против ...)

Как насчет:

var noDupes = list.Distinct().ToList();

В .net 3.5?

Дублирует ли список?

darkgaze 28.05.2019 17:20

@darkgaze просто создает еще один список только с уникальными записями. Таким образом, любые дубликаты будут удалены, и у вас останется список, в котором каждая позиция имеет свой объект.

hexagod 04.10.2019 20:33

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

venkat 20.01.2020 00:10

Если вы используете .Net 3+, вы можете использовать Linq.

List<T> withDupes = LoadSomeData();
List<T> noDupes = withDupes.Distinct().ToList();

Этот код завершится ошибкой, поскольку .Distinct () возвращает IEnumerable <T>. Вы должны добавить к нему .ToList ().

ljs 07.09.2008 00:21

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

Polaris 08.11.2010 10:06

Нет, он работает со списками, содержащими объекты любого типа. Но вам придется переопределить компаратор по умолчанию для вашего типа. Примерно так: public override bool Equals (object obj) {...}

BaBu 09.12.2010 17:27

Всегда полезно переопределить ToString () и GetHashCode () своими классами, чтобы такие вещи работали.

B Seven 08.04.2011 20:58

Вы также можете использовать пакет MoreLinQ Nuget, который имеет метод расширения .DistinctBy (). Довольно полезно.

yu_ominae 16.05.2013 06:49

Не гарантируется, что Distinct сохранит порядок, зависит от реализации

Tod Cunningham 29.05.2020 20:15

Мой требуемый список <MyType> noDupes = withDupes.Distinct (new MyType ()). ToList (); чтобы работать.

John Kurtz 22.01.2021 15:07

Как сказал kronoz в .Net 3.5, вы можете использовать Distinct().

В .Net 2 вы можете имитировать это:

public IEnumerable<T> DedupCollection<T> (IEnumerable<T> input) 
{
    var passedValues = new HashSet<T>();

    // Relatively simple dupe check alg used as example
    foreach(T item in input)
        if (passedValues.Add(item)) // True if item is new
            yield return item;
}

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

Обычно гораздо быстрее фильтровать коллекцию (как это делают и Distinct(), и этот образец), чем удалять из нее элементы.

Проблема с этим подходом заключается в том, что он O (N ^ 2) -ш, в отличие от хеш-набора. Но по крайней мере очевидно, что он делает.

Tamas Czinege 29.01.2009 21:25

@DrJokepu - на самом деле я не осознавал, что конструктор HashSet выполняет дедупликацию, что делает его лучше в большинстве случаев. Однако это сохранит порядок сортировки, которого нет в HashSet.

Keith 24.08.2010 18:59

HashSet <T> был представлен в 3.5

thorn̈ 05.11.2011 23:00

@thorn правда? Так сложно уследить. В этом случае вы можете просто использовать Dictionary<T, object>, заменив .Contains на .ContainsKey и .Add(item) на .Add(item, null).

Keith 07.11.2011 02:32

@Keith, согласно моему тестированию, HashSet сохраняет порядок, а Distinct() - нет.

Dennis T --Reinstate Monica-- 09.06.2015 18:50

@DennisT HashSet иногда делает, в зависимости от типа используемого ключа и относительного порядка ввода. Фрагмент DedupCollection вернет результаты в том же порядке, в котором они были.

Keith 09.06.2015 20:21

@Keith, хорошо, HashSet, похоже, сохраняет порядок, по крайней мере, для int. Вы знаете, для чего еще он работает, а для чего не работает? Я бы проверил себя, но сейчас нет времени.

Dennis T --Reinstate Monica-- 11.06.2015 18:57

Просто инициализируйте HashSet списком того же типа:

var noDupes = new HashSet<T>(withDupes);

Или, если вы хотите вернуть список:

var noDupsList = new HashSet<T>(withDupes).ToList();

... и если вам нужен List<T>, используйте new HashSet<T>(withDupes).ToList()

Tim Schmelter 09.02.2017 19:29

Метод расширения может быть достойным способом ... примерно так:

public static List<T> Deduplicate<T>(this List<T> listToDeduplicate)
{
    return listToDeduplicate.Distinct().ToList();
}

А потом вызовите вот так, например:

List<int> myFilteredList = unfilteredList.Deduplicate();

Другой способ в .Net 2.0

    static void Main(string[] args)
    {
        List<string> alpha = new List<string>();

        for(char a = 'a'; a <= 'd'; a++)
        {
            alpha.Add(a.ToString());
            alpha.Add(a.ToString());
        }

        Console.WriteLine("Data :");
        alpha.ForEach(delegate(string t) { Console.WriteLine(t); });

        alpha.ForEach(delegate (string v)
                          {
                              if (alpha.FindAll(delegate(string t) { return t == v; }).Count > 1)
                                  alpha.Remove(v);
                          });

        Console.WriteLine("Unique Result :");
        alpha.ForEach(delegate(string t) { Console.WriteLine(t);});
        Console.ReadKey();
    }

Вот метод расширения для удаления соседних дубликатов на месте. Сначала вызовите Sort () и передайте тот же IComparer. Это должно быть более эффективным, чем версия Лассе В. Карлсена, которая многократно вызывает RemoveAt (что приводит к перемещению нескольких блоков памяти).

public static void RemoveAdjacentDuplicates<T>(this List<T> List, IComparer<T> Comparer)
{
    int NumUnique = 0;
    for (int i = 0; i < List.Count; i++)
        if ((i == 0) || (Comparer.Compare(List[NumUnique - 1], List[i]) != 0))
            List[NumUnique++] = List[i];
    List.RemoveRange(NumUnique, List.Count - NumUnique);
}

Есть много способов решения - проблема с дубликатами в Списке, ниже один из них:

List<Container> containerList = LoadContainer();//Assume it has duplicates
List<Container> filteredList = new  List<Container>();
foreach (var container in containerList)
{ 
  Container duplicateContainer = containerList.Find(delegate(Container checkContainer)
  { return (checkContainer.UniqueId == container.UniqueId); });
   //Assume 'UniqueId' is the property of the Container class on which u r making a search

    if (!containerList.Contains(duplicateContainer) //Add object when not found in the new class object
      {
        filteredList.Add(container);
       }
  }

Ваше здоровье Рави Ганесан

Вот простое решение, которое не требует какого-либо трудночитаемого LINQ или какой-либо предварительной сортировки списка.

   private static void CheckForDuplicateItems(List<string> items)
    {
        if (items == null ||
            items.Count == 0)
            return;

        for (int outerIndex = 0; outerIndex < items.Count; outerIndex++)
        {
            for (int innerIndex = 0; innerIndex < items.Count; innerIndex++)
            {
                if (innerIndex == outerIndex) continue;
                if (items[outerIndex].Equals(items[innerIndex]))
                {
                    // Duplicate Found
                }
            }
        }
    }

С помощью этого метода у вас будет больше контроля над повторяющимися элементами. Даже больше, если у вас есть база данных, которую нужно обновить. Почему для innerIndex не начинать с outerIndex + 1 вместо того, чтобы каждый раз начинать с начала?

Nolmë Informatique 22.04.2017 13:16

Может быть проще просто убедиться, что дубликаты не добавляются в список.

if (items.IndexOf(new_item) < 0) 
    items.add(new_item)

Сейчас я делаю это так, но чем больше у вас записей, тем дольше длится проверка на наличие дубликатов.

Robert Strauch 24.06.2013 18:59

У меня здесь такая же проблема. Я использую метод List<T>.Contains каждый раз, но с более чем 1 000 000 записей. Этот процесс замедляет работу моего приложения. Вместо этого я сначала использую List<T>.Distinct().ToList<T>().

RPDeshaies 03.01.2014 23:05

Этот метод очень медленный

darkgaze 28.05.2019 17:22

Мне нравится использовать эту команду:

List<Store> myStoreList = Service.GetStoreListbyProvince(provinceId)
                                                 .GroupBy(s => s.City)
                                                 .Select(grp => grp.FirstOrDefault())
                                                 .OrderBy(s => s.City)
                                                 .ToList();

В моем списке есть эти поля: Id, StoreName, City, PostalCode Я хотел показать список городов в раскрывающемся списке с повторяющимися значениями. Решение: сгруппируйте по городам, затем выберите первый в списке.

Я надеюсь, что это помогает :)

Это сработало для случая, когда у меня было несколько элементов с одним и тем же ключом, и мне пришлось оставить только тот, у которого была самая последняя дата обновления. Так что подход, использующий «отдельный», не сработает.

Paul Evans 27.10.2020 07:01

У меня это сработало. просто используйте

List<Type> liIDs = liIDs.Distinct().ToList<Type>();

Замените "Тип" желаемым типом, например внутр.

Distinct находится в Linq, а не в System.Collections.Generic, как сообщается на странице MSDN.

Almo 01.10.2014 23:54

Этот ответ (2012 г.) кажется таким же, как два других ответа на этой странице, относящиеся к 2008 г.?

Jon Schneider 07.01.2016 00:33

Ответ Дэвида Дж. - хороший метод, нет необходимости в дополнительных объектах, сортировке и т.д. Однако его можно улучшить:

for (int innerIndex = items.Count - 1; innerIndex > outerIndex ; innerIndex--)

Таким образом, внешний цикл идет вверху вниз для всего списка, а внутренний цикл идет вниз, «пока не будет достигнута позиция внешнего цикла».

Внешний цикл обеспечивает обработку всего списка, внутренний цикл находит фактические дубликаты, это может произойти только в той части, которую внешний цикл еще не обработал.

Или, если вы не хотите делать внутренний цикл снизу вверх, вы можете запустить внутренний цикл с outerIndex + 1.

  public static void RemoveDuplicates<T>(IList<T> list )
  {
     if (list == null)
     {
        return;
     }
     int i = 1;
     while(i<list.Count)
     {
        int j = 0;
        bool remove = false;
        while (j < i && !remove)
        {
           if (list[i].Equals(list[j]))
           {
              remove = true;
           }
           j++;
        }
        if (remove)
        {
           list.RemoveAt(i);
        }
        else
        {
           i++;
        }
     }  
  }

В качестве вспомогательного метода (без Linq):

public static List<T> Distinct<T>(this List<T> list)
{
    return (new HashSet<T>(list)).ToList();
}

Я думаю, что Distinct уже занят. Кроме того (если вы переименуете метод), он должен работать.

Andreas Reiff 05.01.2015 15:34

Установив пакет ПодробнееLINQ через Nuget, вы можете легко разделить список объектов по свойству

IEnumerable<Catalogue> distinctCatalogues = catalogues.DistinctBy(c => c.CatalogueCode); 

Вы можете использовать Union

obj2 = obj1.Union(obj1).ToList();

Объяснение Почему, это сработает, определенно улучшит этот ответ

Igor B 06.08.2017 18:26

Use Linq's Union method.

Примечание. Это решение не требует знания Linq, кроме того, что он существует.

Код

Начните с добавления следующего в начало файла класса:

using System.Linq;

Теперь вы можете использовать следующее для удаления дубликатов из объекта obj1:

obj1 = obj1.Union(obj1).ToList();

Примечание: переименуйте obj1 в имя вашего объекта.

Как это устроено

  1. Команда Union выводит по одной из каждой записи двух исходных объектов. Поскольку obj1 является обоими исходными объектами, это сокращает obj1 до одной из каждой записи.

  2. ToList() возвращает новый список. Это необходимо, потому что команды Linq, такие как Union, возвращают результат как результат IEnumerable вместо того, чтобы изменять исходный список или возвращать новый список.

Простая интуитивно понятная реализация:

public static List<PointF> RemoveDuplicates(List<PointF> listPoints)
{
    List<PointF> result = new List<PointF>();

    for (int i = 0; i < listPoints.Count; i++)
    {
        if (!result.Contains(listPoints[i]))
            result.Add(listPoints[i]);
        }

        return result;
    }

Этот метод тоже медленный. Создает новый список.

darkgaze 28.05.2019 17:23

Если у вас есть классы буксировки Product и Customer, и мы хотим удалить повторяющиеся элементы из их списка

public class Product
{
    public int Id { get; set; }
    public string ProductName { get; set; }
}

public class Customer
{
    public int Id { get; set; }
    public string CustomerName { get; set; }

}

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

public class ItemEqualityComparer<T> : IEqualityComparer<T> where T : class
{
    private readonly PropertyInfo _propertyInfo;

    public ItemEqualityComparer(string keyItem)
    {
        _propertyInfo = typeof(T).GetProperty(keyItem, BindingFlags.GetProperty | BindingFlags.Instance | BindingFlags.Public);
    }

    public bool Equals(T x, T y)
    {
        var xValue = _propertyInfo?.GetValue(x, null);
        var yValue = _propertyInfo?.GetValue(y, null);
        return xValue != null && yValue != null && xValue.Equals(yValue);
    }

    public int GetHashCode(T obj)
    {
        var propertyValue = _propertyInfo.GetValue(obj, null);
        return propertyValue == null ? 0 : propertyValue.GetHashCode();
    }
}

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

var products = new List<Product>
            {
                new Product{ProductName = "product 1" ,Id = 1,},
                new Product{ProductName = "product 2" ,Id = 2,},
                new Product{ProductName = "product 2" ,Id = 4,},
                new Product{ProductName = "product 2" ,Id = 4,},
            };
var productList = products.Distinct(new ItemEqualityComparer<Product>(nameof(Product.Id))).ToList();

var customers = new List<Customer>
            {
                new Customer{CustomerName = "Customer 1" ,Id = 5,},
                new Customer{CustomerName = "Customer 2" ,Id = 5,},
                new Customer{CustomerName = "Customer 2" ,Id = 5,},
                new Customer{CustomerName = "Customer 2" ,Id = 5,},
            };
var customerList = customers.Distinct(new ItemEqualityComparer<Customer>(nameof(Customer.Id))).ToList();

этот код удаляет повторяющиеся элементы с помощью Id, если вы хотите удалить повторяющиеся элементы с помощью другого свойства, вы можете изменить nameof(YourClass.DuplicateProperty) на тот же nameof(Customer.CustomerName), а затем удалить повторяющиеся элементы с помощью свойства CustomerName.

Это берет отдельные (элементы без дублирующих элементов) и снова преобразует их в список:

List<type> myNoneDuplicateValue = listValueWithDuplicate.Distinct().ToList();

Все ответы копируют списки, или создают новый список, или используют медленные функции, или просто очень медленные.

Насколько я понимаю, это самый быстрый и дешевый способ, который я знаю (также поддерживаемый очень опытным программистом, специализирующимся на оптимизации физики в реальном времени).

// Duplicates will be noticed after a sort O(nLogn)
list.Sort();

// Store the current and last items. Current item declaration is not really needed, and probably optimized by the compiler, but in case it's not...
int lastItem = -1;
int currItem = -1;

int size = list.Count;

// Store the index pointing to the last item we want to keep in the list
int last = size - 1;

// Travel the items from last to first O(n)
for (int i = last; i >= 0; --i)
{
    currItem = list[i];

    // If this item was the same as the previous one, we don't want it
    if (currItem == lastItem)
    {
        // Overwrite last in current place. It is a swap but we don't need the last
       list[i] = list[last];

        // Reduce the last index, we don't want that one anymore
        last--;
    }

    // A new item, we store it and continue
    else
        lastItem = currItem;
}

// We now have an unsorted list with the duplicates at the end.

// Remove the last items just once
list.RemoveRange(last + 1, size - last - 1);

// Sort again O(n logn)
list.Sort();

Окончательная стоимость:

nlogn + n + nlogn = n + 2nlogn = O (nlogn), что довольно приятно.

Примечание о RemoveRange: Поскольку мы не можем установить счетчик в списке и избежать использования функций удаления, я точно не знаю скорость этой операции, но я думаю, что это самый быстрый способ.

Думаю, самый простой способ:

Создайте новый список и добавьте уникальный элемент.

Пример:

        class MyList{
    int id;
    string date;
    string email;
    }
    
    List<MyList> ml = new Mylist();

ml.Add(new MyList(){
id = 1;
date = "2020/09/06";
email = "zarezadeh@gmailcom"
});

ml.Add(new MyList(){
id = 2;
date = "2020/09/01";
email = "zarezadeh@gmailcom"
});

 List<MyList> New_ml = new Mylist();

foreach (var item in ml)
                {
                    if (New_ml.Where(w => w.email == item.email).SingleOrDefault() == null)
                    {
                        New_ml.Add(new MyList()
                        {
                          id = item.id,
     date = item.date,
               email = item.email
                        });
                    }
                }

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