Подтвердить что ты не робот

Проверка дубликатов в списке объектов С#

Я ищу очень быстрый способ проверить дубликаты в списке объектов.

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

Предположим, что у меня есть объект...

public class dupeCheckee
{
     public string checkThis { get; set; }
     public string checkThat { get; set; }

     dupeCheckee(string val, string val2)
     {
         checkThis = val;
         checkThat = val2;
     }
}

И у меня есть список этих объектов

List<dupeCheckee> dupList = new List<dupeCheckee>();
dupList.Add(new dupeCheckee("test1", "value1"));
dupList.Add(new dupeCheckee("test2", "value1"));
dupList.Add(new dupeCheckee("test3", "value1"));
dupList.Add(new dupeCheckee("test1", "value1"));//dupe
dupList.Add(new dupeCheckee("test2", "value1"));//dupe... 
dupList.Add(new dupeCheckee("test4", "value1"));
dupList.Add(new dupeCheckee("test5", "value1"));
dupList.Add(new dupeCheckee("test1", "value2"));//not dupe

Мне нужно найти дубликатов в этом списке. Когда я нахожу это, мне нужно сделать дополнительную логику не обязательно удаляя их.

Когда я использую linq, как мой GroupBy бросает исключение...

'System.Collections.Generic.List<dupeCheckee>' does not contain a definition for 'GroupBy' and no extension method 'GroupBy' accepting a first argument of type 'System.Collections.Generic.List<dupeCheckee>' could be found (are you missing a using directive or an assembly reference?)

Что говорит мне, что мне не хватает библиотеки. Мне сложно определить, какой из них.

Как только я это выясню, как бы я по существу проверял эти два условия... IE checkThis и checkThat оба происходят более одного раза?

ОБНОВЛЕНИЕ: что я придумал

Это запрос linq, с которым я столкнулся после выполнения быстрых исследований...

test.Count != test.Select(c => new { c.checkThat, c.checkThis }).Distinct().Count()

Я не уверен, что это определенно лучше, чем этот ответ...

var duplicates = test.GroupBy(x => new {x.checkThis, x.checkThat})
                   .Where(x => x.Skip(1).Any());

Я знаю, что могу поставить первый оператор в условие if else. Я также проверил быструю проверку. Список дубликатов возвращает мне 1, когда я ожидал 0, но он правильно назвал тот факт, что у меня были дубликаты в одном из наборов, которые я использовал...

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

Повторные:

List<DupeCheckee> test = new List<DupeCheckee>{ 
     new DupeCheckee("test0", "test1"),//{ checkThis = "test", checkThat = "test1"}
     new DupeCheckee("test1", "test2"),//{ checkThis = "test", checkThat = "test1"}
     new DupeCheckee("test2", "test3"),//{ checkThis = "test", checkThat = "test1"}
     new DupeCheckee("test3", "test3"),//{ checkThis = "test", checkThat = "test1"}
     new DupeCheckee("test0", "test5"),//{ checkThis = "test", checkThat = "test1"}
     new DupeCheckee("test1", "test6"),//{ checkThis = "test", checkThat = "test1"}
     new DupeCheckee("test2", "test7"),//{ checkThis = "test", checkThat = "test1"}
     new DupeCheckee("test3", "test8"),//{ checkThis = "test", checkThat = "test1"}
     new DupeCheckee("test0", "test5"),//{ checkThis = "test", checkThat = "test1"}
     new DupeCheckee("test1", "test1"),//{ checkThis = "test", checkThat = "test1"}
     new DupeCheckee("test2", "test2"),//{ checkThis = "test", checkThat = "test1"}
     new DupeCheckee("test3", "test3"),//{ checkThis = "test", checkThat = "test1"}
     new DupeCheckee("test4", "test4"),//{ checkThis = "test", checkThat = "test1"}

};

Нет обманов...

     List<DupeCheckee> test2 = new List<DupeCheckee>{ 
     new DupeCheckee("test0", "test1"),//{ checkThis = "test", checkThat = "test1"}
     new DupeCheckee("test1", "test2"),//{ checkThis = "test", checkThat = "test1"}
     new DupeCheckee("test2", "test3"),//{ checkThis = "test", checkThat = "test1"}
     new DupeCheckee("test3", "test3"),//{ checkThis = "test", checkThat = "test1"}
     new DupeCheckee("test4", "test5"),//{ checkThis = "test", checkThat = "test1"}
     new DupeCheckee("test5", "test6"),//{ checkThis = "test", checkThat = "test1"}
     new DupeCheckee("test6", "test7"),//{ checkThis = "test", checkThat = "test1"}
     new DupeCheckee("test7", "test8"),//{ checkThis = "test", checkThat = "test1"}
     new DupeCheckee("test8", "test5"),//{ checkThis = "test", checkThat = "test1"}
     new DupeCheckee("test9", "test1"),//{ checkThis = "test", checkThat = "test1"}
     new DupeCheckee("test2", "test2"),//{ checkThis = "test", checkThat = "test1"}
     new DupeCheckee("test3", "test3"),//{ checkThis = "test", checkThat = "test1"}
     new DupeCheckee("test4", "test4"),//{ checkThis = "test", checkThat = "test1"}

};
4b9b3361

Ответ 1

Вам нужно обратиться к System.Linq(например, using System.Linq)

то вы можете сделать

var dupes = dupList.GroupBy(x => new {x.checkThis, x.checkThat})
                   .Where(x => x.Skip(1).Any());

Это даст вам группы со всеми дубликатами

Тогда тест на дубликаты будет

var hasDupes = dupList.GroupBy(x => new {x.checkThis, x.checkThat})
                   .Where(x => x.Skip(1).Any()).Any();

или даже вызовите ToList() или ToArray(), чтобы заставить вычислять результат, а затем вы можете проверить наличие обмана и изучить их.

например..

var dupes = dupList.GroupBy(x => new {x.checkThis, x.checkThat})
                   .Where(x => x.Skip(1).Any()).ToArray();
if (dupes.Any()) {
  foreach (var dupeList in dupes) {
    Console.WriteLine(string.Format("checkThis={0},checkThat={1} has {2} duplicates",
                      duplist.Key.checkThis, 
                      duplist.Key.checkThat,
                      duplist.Count() - 1));
  }

}

В качестве альтернативы

var dupes = dupList.Select((x, i) => new { index = i, value = x})
                   .GroupBy(x => new {x.value.checkThis, x.value.checkThat})
                   .Where(x => x.Skip(1).Any());

Что дает вам группы, каждый элемент каждой группы сохраняет исходный индекс в свойстве index и элемент в свойстве value

Ответ 2

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

var hasDuplicatedEntries = ListWithPossibleDuplicates
                                   .GroupBy(YourGroupingExpression)
                                   .Any(e => e.Count() > 1);
if(hasDuplicatedKeys)
{
   // Do what ever you want in case when list contains duplicates 
}

Ответ 3

Я думаю, что это то, что вы ищете:

List<dupeChecke> duplicates = dupeList.GroupBy(x => x)
                                   .SelectMany(g => g.Skip(1));

Ответ 4

Сделайте выделение, отличное от linq, например. Как я могу выполнить SELECT UNIQUE с LINQ?

И затем сравните числа отдельных результатов с нечеткими результатами. Это даст вам логическое высказывание, если список имеет удвоение.

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

Ответ 5

В объектах памяти я всегда использую метод Distinct LINQ, добавляющий сравнение с решением.

public class dupeCheckee
{
     public string checkThis { get; set; }
     public string checkThat { get; set; }

     dupeCheckee(string val, string val2)
     {
         checkThis = val;
         checkThat = val2;
     }

     public class Comparer : IEqualityComparer<dupeCheckee>
     {
         public bool Equals(dupeCheckee x, dupeCheckee y)
         {
             if (x == null || y == null)
                 return false;

             return x.CheckThis == y.CheckThis && x.CheckThat == y.CheckThat;
         }

         public int GetHashCode(dupeCheckee obj)
         {
             if (obj == null)
                 return 0;

             return (obj.CheckThis == null ? 0 : obj.CheckThis.GetHashCode()) ^
                 (obj.CheckThat == null ? 0 : obj.CheckThat.GetHashCode());
         }
     }
}

Теперь мы можем назвать

List<dupeCheckee> dupList = new List<dupeCheckee>();
dupList.Add(new dupeCheckee("test1", "value1"));
dupList.Add(new dupeCheckee("test2", "value1"));
dupList.Add(new dupeCheckee("test3", "value1"));
dupList.Add(new dupeCheckee("test1", "value1"));//dupe
dupList.Add(new dupeCheckee("test2", "value1"));//dupe... 
dupList.Add(new dupeCheckee("test4", "value1"));
dupList.Add(new dupeCheckee("test5", "value1"));
dupList.Add(new dupeCheckee("test1", "value2"));//not dupe

var distinct = dupList.Distinct(dupeCheckee.Comparer);

Ответ 6

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

string text = "this is some text";

var hasDupes = text.GroupBy(x => x).Any(grp => grp.Count() > 1);

Если вы хотите узнать, сколько дубликатов есть независимо от того, что такое дубликаты, используйте это.

var totalDupeItems = text.GroupBy(x => x).Count(grp =>  grp.Count() > 1);

Так, например, "это какой-то текст" имеет это...

всего буквы t: 3

итог буквы i: 2

всего буквы s: 3

всего буквы e: 2

Таким образом, переменная totalDupeItems будет равна 4. Существует 4 разных типа дубликатов.

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

var totalDupes = letters.GroupBy(x => x).Where(grp => grp.Count() > 1).Sum(grp => grp.Count());

Таким образом, переменная totalDupes будет равна 10. Это общие повторяющиеся элементы каждого типа дублирования, добавленные вместе.

Ответ 7

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

try
{
  dupList.ToDictionary(a=>new {a.checkThis,a.checkThat});
}
catch{
 //message: list items is not uniqe
}