【问题标题】:how to check if object already exists in a list如何检查对象是否已存在于列表中
【发布时间】:2010-08-08 16:28:02
【问题描述】:

我有一个清单

  List<MyObject> myList

我正在将项目添加到列表中,并且我想检查该对象是否已经在列表中。

所以在我这样做之前:

 myList.Add(nextObject);

我想看看 nextObject 是否已经在列表中。

对象“MyObject”有许多属性,但比较是基于两个属性的匹配。

在我将新的“MyObject”添加到“MyObject”列表之前,最好的检查方法是什么。

我想到的唯一解决方案是从列表更改为字典,然后将键设为属性的串联字符串(这似乎有点不雅)。

任何其他使用列表或 LINQ 或其他东西的更清洁的解决方案?

【问题讨论】:

    标签: c# linq list


    【解决方案1】:

    这取决于具体情况的需要。例如,字典方法会很好假设:

    1. 列表相对稳定(插入/删除不是很多,字典没有针对哪些优化)
    2. 列表非常大(否则字典的开销毫无意义)。

    如果上述情况不适合您的情况,请使用方法Any():

    Item wonderIfItsPresent = ...
    bool containsItem = myList.Any(item => item.UniqueProperty == wonderIfItsPresent.UniqueProperty);
    

    这将遍历列表,直到找到匹配项,或者直到它到达末尾。

    【讨论】:

    • 为 list.exists 使用谓词委托是另一种解决方案,见下文,但如果您有巨大的列表并且使用字典的键值会更快,因为它是一个哈希表!享受
    • 如何检查多个值?
    • 此解决方案仅适用于 .NET 5.0+ 。遗憾的是,我们中的一些人没有这个版本。 :-(
    【解决方案2】:

    只需使用Contains 方法。请注意,它基于相等函数Equals

    bool alreadyExist = list.Contains(item);
    

    【讨论】:

    • 这对我不起作用,它总是说它不存在
    • @Si8 如果您尝试比较对象,则必须确保 IEquatable.Equals 实现针对您的对象类型正确实现。否则,您将不会比较对象内容。有关如何实现此功能的示例,请参阅 Ahmad 指示的包含链接。
    • list.countains 不能在这里使用,因为它会为 dev1、dev11、dev111... 等报告 true
    • @FranckE - 听起来您没有正确设置 IEquatable 来检查包含的内容。
    • 当它是一个对象列表时不起作用,但它是一个字符串列表时起作用
    【解决方案3】:

    如果使用这两个属性是可维护的,您可以:

    bool alreadyExists = myList.Any(x=> x.Foo=="ooo" && x.Bar == "bat");
    

    【讨论】:

    • 仅来自 .Net 5 +
    【解决方案4】:

    您确定在这种情况下需要一份清单吗?如果您在列表中填充了许多项目,myList.ContainsmyList.Any 会影响性能;运行时间将是二次的。您可能需要考虑使用更好的数据结构。例如,

     public class MyClass
        {
            public string Property1 { get; set; }
            public string Property2 { get; set; }
    
        }
    
        public class MyClassComparer : EqualityComparer<MyClass>
        {
            public override bool Equals(MyClass x, MyClass y)
            {
                if(x == null || y == null)
                   return x == y;
    
                return x.Property1 == y.Property1 && x.Property2 == y.Property2;
            }
    
            public override int GetHashCode(MyClass obj)
            {
                return obj == null ? 0 : (obj.Property1.GetHashCode() ^ obj.Property2.GetHashCode());
            }
        }
    

    您可以通过以下方式使用 HashSet:

      var set = new HashSet<MyClass>(new MyClassComparer());
      foreach(var myClass in ...)
         set.Add(myClass);
    

    当然,如果MyClass 的相等定义是“通用的”,你就不需要编写IEqualityComparer 实现;您可以在类本身中覆盖 GetHashCodeEquals

    【讨论】:

    • 是的,V 的 bool 是我最喜欢的。就此而言,不久前(嗯,大约 3 周)我无法使用 HashSet,因为我正在编写 2.0 代码,我放弃了 HashSet 的 Mono 实现,因为它非常有用:)
    【解决方案5】:

    另外一点要提的是,你应该确保你的相等函数是你所期望的。您应该重写 equals 方法来设置对象的哪些属性必须匹配才能使两个实例被视为相等。

    那你就可以了 mylist.contains(item)

    【讨论】:

      【解决方案6】:

      这是一个快速控制台应用程序,用于描述如何解决您的问题的概念。

      using System;
      using System.Collections.Generic;
      using System.Linq;
      using System.Text;
      
      namespace ConsoleApplication3
      {
          public class myobj
          {
              private string a = string.Empty;
              private string b = string.Empty;
      
              public myobj(string a, string b)
              {
                  this.a = a;
                  this.b = b;
              }
      
              public string A
              {
                  get
                  {
                      return a;
                  }
              }
      
              public string B
              {
                  get
                  {
                      return b;
                  }
              }
          }
      
      
          class Program
          {
              static void Main(string[] args)
              {
                  List<myobj> list = new List<myobj>();
                  myobj[] objects = { new myobj("a", "b"), new myobj("c", "d"), new myobj("a", "b") };
      
      
                  for (int i = 0; i < objects.Length; i++)
                  {
                      if (!list.Exists((delegate(myobj x) { return (string.Equals(x.A, objects[i].A) && string.Equals(x.B, objects[i].B)) ? true : false; })))
                      {
                          list.Add(objects[i]);
                      }
                  }
              }
          }
      }
      

      享受吧!

      【讨论】:

        【解决方案7】:

        编辑:我先说:


        字典解决方案有什么不雅之处?这对我来说似乎非常优雅,尤其是因为您只需要在创建字典时设置比较器。


        当然,当它也是值时,将它用作键是不雅的。

        因此我会使用 HashSet。如果以后的操作需要索引,我会在添加完成后从中创建一个列表,否则,只需使用哈希集。

        【讨论】:

        • 我只会在对象列表很大时使用它,因为它是一个哈希表,并且它们非常适合快速查找。
        【解决方案8】:

        简单但有效

        MyList.Remove(nextObject)
        MyList.Add(nextObject)
        

         if (!MyList.Contains(nextObject))
            MyList.Add(nextObject);
        

        【讨论】:

          【解决方案9】:

          集合可以用作字典,不同之处在于您不需要引用 Microsoft Scripting Runtime 或使用后期绑定。请注意,在这种情况下,键必须是字符串。在我的情况下,键(数字)是整数,但声明为字符串。 您可以创建一个自定义布尔函数来检查该键是否存在于列表中。 ExcelMacroMastery.com 上的 Paul Kelly 有一篇好文章

          ' Function to check if item in the collection already exists
          Function Exists(coll As Collection, key As String) As Boolean
          
              On Error GoTo EH
          
              IsObject (coll.Item(key))
              Exists = True
          
          EH:
          End Function
          

          你可以这样使用它

          For i = 3 To lastRow
              
                  ' Ignore the Normal areas
                  If rg.Cells(i, 1).value <> "Normal" Then
                  
                      number = rg.Cells(i, 1).value
                      
                      ' Check if the area exist in the collection using a custom function Exists
                      If Exists(coll, number) = False Then
                      
                          Set oRiskArea = New clsHighRiskArea
                          oRiskArea.number = number
                          coll.add key:=oRiskArea.number, Item:=oRiskArea
                          
                      Else
                          Set oRiskArea = coll(number)
                      End If
                      
                      With oRiskArea
                  
                          .name = rg.Cells(i, 2).value
                  
                      End With
                      
                  End If
          
              Next i
          

          【讨论】:

            猜你喜欢
            • 2018-01-06
            • 2016-04-02
            • 2012-09-26
            • 1970-01-01
            • 1970-01-01
            • 2017-02-24
            • 1970-01-01
            • 1970-01-01
            相关资源
            最近更新 更多