2013-04-24 3 views
18

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

Я думал просто пробегаем по списку и делать ручного сравнения, что путь, но я подумал, что 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 оба происходят более одного раза?

UPDATE: То, что я придумал

Это 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

Добавить 'using System.Linq;' в начало вашего файла cs для работы 'GroupBy'. –

+0

yep. Просто понял, что мне это не хватает. Благодарю. – SoftwareSavant

+2

Erm Нет, у обманов нет дуэта test3, test3 –

ответ

30

Вам необходимо обратиться к 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

+0

Я действительно смотрю, есть ли у предмета какие-либо обманы. Было бы неплохо иметь несколько «Список » со всеми дубликатами в них ... Это будет хорошо, если пользователь захочет удалить их позже, но я действительно просто хочу проверить, нет ли в списке обманов. – SoftwareSavant

+0

@DmainEvent То, что это делает? Если вы хотите проверить, есть ли какие-либо обманщики, просто проверьте 'dupes.Any()', если true, есть дубликаты –

+0

Не могли бы вы взглянуть на мое решение и посмотреть, не обнаружите ли что-либо недостающее в моем решении. Я пробовал как твои, так и мои, у меня все нормально ... Не уверен в твоем. – SoftwareSavant

0

сделать выбор отчетливый с помощью LINQ, например, How can I do SELECT UNIQUE with LINQ?

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

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

+0

Если он хочет что-то сделать с обманами, GroupBy - лучший подход. –

+0

@ Daniel Опубликуйте это как ответ, чтобы я мог его продвинуть, и пользователь может отметить это как ответ! – MatthewMartin

1

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

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

Это работает только если проверка равенства на 'dupeCheckee' идентифицирует экземпляры как равным, где 'checkThis' и' checkThat' равны. –

+0

@BobVale: Не заметил, что он хотел сломать еще больше! Ваш комментарий сохранен. –

0

Для объектов памяти я всегда использую метод LINK , добавляя сравнение с решением.

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); 
+0

Это получает отдельный список, но я ищу, чтобы выяснить, есть ли в моем списке обманы. – SoftwareSavant

0

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

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

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

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

всего письма я: 2

всего письма s : 3

всего буквой е: 2

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

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

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

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

5

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

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

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

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