Сравните элементы в двух списках и замените foreach l oop на LINQ - PullRequest
0 голосов
/ 24 февраля 2020

У меня есть два списка:

   List<Item1> list1;
   List<Item2> list2;

У меня есть следующий код для конкурирующих предметов в списках:

ConcurrentDictionary<string, string> compareDictionary = new ConcurrentDictionary<string, string>();

for (int i = 0; i < lis1.Count; i++)
{
   var item1Name= list1[i].Name.ToString();
   var item1Id= list1[i].ID.ToString();

   foreach (var item in list2)
   {
      if (item1Name.Contains(item.item2Name.ToLower()))
      {
          compareDictionary.TryAdd(item1Id, item.item2Id);
      }
    }
}

Необходимо добавить Id из первого списка и Id из второго в ConcurrentDictionary, если Name одного элемента содержит часть другого. Это работает, но я хочу упростить алгоритм и убрать foreach и if.

Ответы [ 2 ]

1 голос
/ 24 февраля 2020

Пара фрагментов кода, чтобы найти совпадения и добавить ids двух объектов в ConcurrentDictionary<string, string>.

Итак, у нас есть:

var dict = new ConcurrentDictionary<string, string>();

Первый

list1.ForEach(x =>
{
    list2.Where(y => y.Item2Name.IndexOf(x.Name, StringComparison.CurrentCultureIgnoreCase) >= 0)
    .ToList().ForEach(y => dict.TryAdd(x.ID, y.Item2Id));
});

Второе

(from x in list1
    from y in list2
    where x.Name.IndexOf(y.Item2Name, StringComparison.CurrentCultureIgnoreCase) >= 0
    select (x, y)).ToList().ForEach(item => dict.TryAdd(item.x.ID, item.y.Item2Id));

Примечание стороны

  • Если оба Свойства Item1.Name и Item2.Item2Name относятся к типу string, поэтому нет необходимости использовать функцию ToString(), как в строке var item1Name= list1[i].Name.ToString();.

  • Если оба Item1.ID и Item2.Item2Id свойства имеют тип int, тогда правильный тип пар Key и Value словаря - это тип int. Итак:

var dict = new ConcurrentDictionary<int, int>();
1 голос
/ 24 февраля 2020

Вы можете избавиться от внутреннего l oop, используя System.Linq. Также упростите код, используя foreach вместо for для основного l oop:

ConcurrentDictionary<string, string> compareDictionary = new ConcurrentDictionary<string, string>();

foreach (var element in list1)
{
   var item1Name= element.Name.ToString();
   var item1Id= element.ID.ToString();
   // If this element has already one correspondence, TryAdd will fail anyway
   if(compareDictionary.ContainsKey(item1Id)) continue; 

   var found = list2.FirstOrDefault(item => item1Name.Contains(item.item2Name.ToLower()));
   if(found != null)
   {
          compareDictionary.TryAdd(item1Id, item.item2Id);
   }
}

В зависимости от именования ваших элементов, вам также может понадобиться сделать item1Name строчным. Ваш код фактически найдет это соответствие:

Parentwithlittlechild --> LittleChild

, но не это:

ParentWithLittleChild --> LittleChild

, потому что LittleChild будет иметь нижний регистр, а String.Contains по умолчанию работает с учетом регистра. Вы также можете использовать метод IndexOf с StringComparison.OrdinalIgnoreCase, например:

var found = list2.FirstOrDefault(item => item1Name.IndexOf(item.item2Name, StringComparison.OrdinalIgnoreCase) >= 0);

Последнее замечание: element.Name, вероятно, уже имеет тип string, если только свойство Item1.Name не является забавным типом. Если это так, element.Name.ToString() конвертируется всего за element.Name.

...