【问题标题】:Compare items in two lists and replace foreach loop with LINQ比较两个列表中的项目并用 LINQ 替换 foreach 循环
【发布时间】:2020-06-08 08:58:12
【问题描述】:

我有两个列表:

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

如果一个项目的Name包含另一个项目的一部分,则需要将第一个列表中的Id和第二个列表中的Id添加到ConcurrentDictionary中。 它有效,但我想简化算法并删除foreachif

【问题讨论】:

  • 你能分享Item1Item1的属性吗?
  • 用 AddRange 将两个列表加入到一起,例如。 list1.AddRange(list2);然后 list1.Distinct()。如果您只想匹配某些属性,则需要创建一个自定义相等比较器,
  • @level_zebra 列表属于不同类型,尝试将列表 2 添加到列表 1 时会出现编译错误。

标签: c# linq for-loop foreach concurrentdictionary


【解决方案1】:

您可以使用 System.Linq 摆脱内部循环。还可以通过使用 foreach 而不是 for for 主循环来简化代码:

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 可能已经是字符串类型,除非您的 Item1.Name 属性是一些有趣的类型。如果是这样,element.Name.ToString() 可以转换为 element.Name

【讨论】:

    【解决方案2】:

    几个代码 sn-ps 来查找匹配项并将两个对象的 ids 添加到 ConcurrentDictionary&lt;string, string&gt; 中。

    所以我们有:

    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.NameItem2.Item2Name 属性都是string 类型,则不需要像var item1Name= list1[i].Name.ToString(); 行中那样使用ToString() 函数。

    • 如果Item1.IDItem2.Item2Id 属性都是int 类型,那么字典中KeyValue 对的正确类型是int 类型。所以:

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

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2013-07-08
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2022-10-20
      • 1970-01-01
      相关资源
      最近更新 更多