【问题标题】:Add items to a collection if the collection does NOT already contain it by comparing a property of the items?如果集合尚未通过比较项目的属性将项目添加到集合中?
【发布时间】:2011-09-13 22:38:12
【问题描述】:

基本上,我该怎么做才能做到类似于:CurrentCollection.Contains(...),除了比较项目的属性是否已经在集合中?

public class Foo
{
    public Int32 bar;
}


ICollection<Foo> CurrentCollection;
ICollection<Foo> DownloadedItems;

//LINQ: Add any downloaded items where the bar Foo.bar is not already in the collection?

【问题讨论】:

    标签: c# linq collections contains


    【解决方案1】:

    您可以调用Any 方法并传递一个值以与集合中对象类型的任何属性进行比较

    if (!CurrentCollection.Any(f => f.bar == someValue))
    {
        // add item
    }
    

    更完整的解决方案可能是:

    DownloadedItems.Where(d => !CurrentCollection.Any(c => c.bar == d.bar)).ToList()
        .ForEach(f => CurrentCollection.Add(f));
    

    【讨论】:

      【解决方案2】:
      var newItems = DownloadedItems.Where(i => !CurrentCollection.Any(c => c.Attr == i.Attr));
      

      【讨论】:

        【解决方案3】:

        你可以这样做:

        CurrentCollection.Any(x => x.bar == yourGivenValue)
        

        【讨论】:

          【解决方案4】:

          您首先要查找集合中尚未包含的元素:

          var newItems = DownloadedItems.Where(x => !CurrentCollection.Any(y => x.bar == y.bar));
          

          然后添加它们:

          foreach(var item in newItems)
          {
              CurrentCollection.Add(item);
          }
          

          请注意,如果DownloadedItems 的大小接近CurrentCollection 的大小,则第一个操作可能具有二次复杂度。如果这最终导致问题(首先测量!),您可以使用HashSet 将复杂性降低到线性:

          // collect all existing values of the property bar
          var existingValues = new HashSet<Foo>(from x in CurrentCollection select x.bar);
          // pick items that have a property bar that doesn't exist yet
          var newItems = DownloadedItems.Where(x => !existingValues.Contains(x.bar));
          // Add them
          foreach(var item in newItems)
          {
              CurrentCollection.Add(item);
          }
          

          【讨论】:

          • 使用 hash-map 方法使我的方法快了 5 倍。
          • 我认为这是最好的做法
          【解决方案5】:

          使用 R.Martinho Fernandes 方法并转换为 1 行:

          CurrentCollection.AddRange(DownloadedItems.Where(x => !CurrentCollection.Any(y => y.bar== x.bar)));
          

          【讨论】:

            【解决方案6】:

            或者使用All

            CurrentCollection
                .AddRange(DownloadedItems.Where(x => CurrentCollection.All(y => y.bar != x.bar)));
            

            【讨论】:

              【解决方案7】:

              你可以使用Enumerable.Except

              它将比较两个列表并返回仅出现在第一个列表中的元素。

              CurrentCollection.AddRange(DownloadedItems.Except(CurrentCollection));
              

              【讨论】:

                【解决方案8】:

                您还可以做的一件事我认为这是最简单的方法是取消 HashSet 而不是 List,默认情况下 HashSet 不添加冗余值。

                【讨论】:

                  【解决方案9】:
                      List<int> current = new List<int> { 1, 2 };
                      List<int> add = new List<int> { 2, 3 };
                      current.AddRange(add.Except(current));
                  

                  这将产生 1,2,3,使用默认比较。
                  如果您更改比较行为,这也适用于 Foo

                      public class Foo : IEquatable<Foo>
                      {
                          public Int32 bar;
                          public bool Equals(Foo other)
                          {
                              return bar == other.bar;
                          }
                          public override bool Equals(object obj) => Equals(obj as Foo);
                          public override int GetHashCode() => (bar).GetHashCode(); // (prop1,prop2,prop3).GetHashCode()
                      }
                  

                  您也可以实现IEqualityComparer&lt;Foo&gt;,并将其作为第二个参数传递给except

                      current.AddRange(add.Except(current, new FooComparer()));
                  
                      public class FooComparer : IEqualityComparer<Foo>
                      {
                          public bool Equals(Foo x, Foo y)
                          {
                              return x.bar.Equals(y.bar);
                          }
                          public int GetHashCode(Foo obj)
                          {
                              return obj.bar.GetHashCode();
                          }
                      }
                  

                  【讨论】:

                    【解决方案10】:
                    internal static class ExtensionMethod
                    {
                        internal static ICollection<T> AddIfExists<T>(this ICollection<T> list, ICollection<T> range)
                        {
                            foreach (T item in range)
                            {
                                if (!list.Contains(item))
                                    list.Add(item);
                            }
                            return list;
                        }
                    }
                    
                    ICollection<Foo> CurrentCollection;
                    ICollection<Foo> DownloadedItems;
                    
                    CurrentCollection.AddIfExists(DownloadedItems)....
                    

                    【讨论】:

                      猜你喜欢
                      • 1970-01-01
                      • 2023-04-08
                      • 2019-08-06
                      • 1970-01-01
                      • 1970-01-01
                      • 1970-01-01
                      • 2015-02-28
                      • 1970-01-01
                      • 1970-01-01
                      相关资源
                      最近更新 更多