C # Определить дубликат в списке - PullRequest
59 голосов
/ 22 февраля 2011

Требование: в несортированном списке определите, существует ли дубликат. Типичный способ сделать это - вложенный цикл с квадратом n. Мне интересно, как другие решают это. Есть ли в Linq элегантный, высокопроизводительный метод? Было бы неплохо что-то общее, что требует лямбда или компаратор.

Ответы [ 11 ]

127 голосов
/ 22 февраля 2011

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

var list = new List<string>();

// Fill the list

if(list.Count != list.Distinct().Count())
{
     // Duplicates exist
}
44 голосов
/ 22 февраля 2011

Согласно статье Эрика Уайта о том, как Найти дубликаты с помощью LINQ :

Простой способ найти дубликаты - написать запрос, который группируется по идентификатору, а затемфильтр для групп, которые имеют более одного члена.В следующем примере мы хотим знать, что 4 и 3 являются дубликатами:

int[] listOfItems = new[] { 4, 2, 3, 1, 6, 4, 3 };
var duplicates = listOfItems
    .GroupBy(i => i)
    .Where(g => g.Count() > 1)
    .Select(g => g.Key);
foreach (var d in duplicates)
    Console.WriteLine(d); // 4,3
20 голосов
/ 22 мая 2014

Чтобы разрешить короткое замыкание, если дубликат существует в начале списка, вы можете добавить HashSet<T> и проверить возвращаемое значение его метода .Add.

Используя .Any, вы можете замкнуть счетчик, как только найдете дубликат.

Вот метод расширения LINQ в C # и VB:

CSharp:

public static bool ContainsDuplicates<T>(this IEnumerable<T> enumerable)
{
    var knownKeys = new HashSet<T>();
    return enumerable.Any(item => !knownKeys.Add(item));
}

Visual Basic:

<Extension>
Public Function ContainsDuplicates(Of T)(ByVal enumerable As IEnumerable(Of T)) As Boolean
    Dim knownKeys As New HashSet(Of T)
    Return enumerable.Any(Function(item) Not knownKeys.Add(item))
End Function

Примечание : чтобы проверить, есть ли нет дубликатов, просто измените Any на All

13 голосов
/ 22 февраля 2011

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

bool hasDuplicates<T>(List<T> myList) {
    var hs = new HashSet<T>();

    for (var i = 0; i < myList.Count; ++i) {
        if (!hs.Add(myList[i])) return true;
    }
    return false;
}

Должно быть более эффективным, чем Distinct, поскольку нет необходимости просматривать весь список.

2 голосов
/ 19 июня 2015

Вы можете использовать метод IEnumerable.GroupBy.

var list = new List<string> {"1", "2","3", "1", "2"};
var hasDuplicates = list.GroupBy(x => x).Any(x => x.Skip(1).Any());
2 голосов
/ 22 февраля 2011

Что-то в этом духе относительно просто и даст вам количество дубликатов.

var something = new List<string>() { "One", "One", "Two", "Three" };

var dictionary = new Dictionary<string, int>();

something.ForEach(s =>
    {
        if (dictionary.ContainsKey(s))
        {
            dictionary[s]++;
        }
        else
        {
            dictionary[s] = 1;
        }
    });

Я полагаю, что это похоже на реализацию Distinct, хотя я не уверен.

1 голос
/ 16 сентября 2014

Использование Enumerable.Any с HashSet.Add, например:

List<string> list = new List<string> {"A", "A", "B", "C", "D"};
HashSet<string> hashSet = new HashSet<string>();
if(list.Any(r => !hashSet.Add(r)))
{
   //duplicate exists. 
}

HashSet.Add вернет false, если элемент уже существует в HashSet.Это не будет повторять весь список.

1 голос
/ 22 февраля 2011

Если вы используете целые числа или упорядоченные множества, используйте двоичное дерево для производительности O (nlog n).

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

1 голос
/ 22 февраля 2011

Вы можете использовать метод расширения Distinct () для IEnumerable

0 голосов
/ 19 мая 2018

Пока никто не видел, так что вот небольшая программа, которую я только что написал.Это достаточно просто.Использование Contains (), хотя я не знаю, насколько масштабируем этот метод.

       Console.WriteLine("Please enter 5 unique numbers....");
        List<int> uniqueNums = new List<int>() { };
        while (uniqueNums.Count < 5)
        {
            int input = Convert.ToInt32(Console.ReadLine());
            if (uniqueNums.Contains(input))
            {
                Console.WriteLine("Add a different number");
            }
            uniqueNums.Add(input);
        }
        uniqueNums.Sort();
        foreach (var n in uniqueNums)
        {
            Console.WriteLine(n);
        }
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...