Найти дубликат в списке с помощью Linq

#c# #asp.net #linq #optimization

#c# #asp.net #linq #оптимизация

Вопрос:

Я создаю список пользователей. у каждого пользователя есть полное имя. Я сравниваю пользователей по полному имени.

я беру DataTable с пользователями из старой базы данных и анализирую их в объект ‘User’. и добавить их в List<Users> . который в коде является List<Deelnemer>

Это выглядит следующим образом:

     List<Deelnemer> tempDeeln = new List<Deelnemer>();
    bool dupes = false;
    foreach (DataRow rij in deeln.Rows) {
            Deelnemer dln = new Deelnemer();
            dln.Dln_Creatiedatum = DateTime.Now;
            dln.Dln_Email = rij["Ler_Email"].ToString();
            dln.Dln_Inst_ID = inst.Inst_ID;
            dln.Dln_Naam = rij["Ler_Naam"].ToString();
            dln.Dln_Username = rij["LerLog_Username"].ToString();
            dln.Dln_Voornaam = rij["Ler_Voornaam"].ToString();
            dln.Dln_Update = (DateTime)rij["Ler_Update"];
            if (!dupes amp;amp; tempDeeln.Count(q => q.FullName.ToLower() == dln.FullName.ToLower()) > 0)
                dupes = true;
            tempDeeln.Add(dln);
     }
  

затем, когда foreach выполнен, я смотрю, имеет ли значение bool значение true, проверяю, какие из них являются двойными, и удаляю самые старые.

теперь, я думаю, что эта часть кода очень плоха:

      if (!dupes amp;amp; tempDeeln.Count(q => q.FullName.ToLower() == dln.FullName.ToLower()) > 0)
  

он выполняется для каждого добавленного пользователя и выполняется для всех уже созданных пользователей.

мой вопрос: как бы мне это оптимизировать.

Ответ №1:

Вы можете использовать набор, такой как HashSet<T> для отслеживания уникальных имен, наблюдаемых до сих пор. Хэш-набор поддерживает вставку и поиск в постоянном времени, поэтому полный линейный поиск не потребуется для каждого нового элемента, в отличие от вашего существующего решения.

 var uniqueNames = new HashSet<string>(StringComparer.CurrentCultureIgnoreCase);
...

foreach(...)
{
   ...

   if(!dupes)
   {
       // Expression is true only if the set already contained the string.
       dupes = !uniqueNames.Add(dln.FullName); 
   }
}
  

Если вы хотите «удалить» дубликаты (т. Е. создать по одному репрезентативному элементу для каждого имени), после того, как вы собрали список (без использования хэш-набора), вы можете сделать:

 var distinctItems = tempDeeln.GroupBy(dln => dln.FullName, 
                                        StringComparer.CurrentCultureIgnoreCase)
                             .Select(g => g.First());
  

Комментарии:

1. Мне нравится решение HashSet, но я не вижу, как может работать решение «select distinct».

2. @Magnus: Ты прав; это было замораживанием мозга. Не уверен, о чем я думал. Спасибо, что указали на это.

Ответ №2:

Ответ №3:

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

 if (!dupes amp;amp; tempDeeln.Any(q => q.FullName.ToLower() == dln.FullName.ToLower()))
            dupes = true;