Проверка дубликатов в списке объектов С#
Я ищу очень быстрый способ проверить дубликаты в списке объектов.
Я думал просто перебирать список и делать ручное сравнение таким образом, но я думал, что 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"}
};
Ответы
Ответ 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
}