如何检查列表中是否已存在对象


102

我有一个清单

  List<MyObject> myList

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

所以在我这样做之前:

 myList.Add(nextObject);

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

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

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

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

还有其他使用list或LINQ或其他方式的清洁解决方案吗?

Answers:


153

这取决于具体情况的需要。例如,假设以下条件,则字典方法将是相当不错的:

  1. 该列表相对稳定(没有大量的插入/删除操作,这些词典未针对其进行优化)
  2. 列表很大(否则字典的开销是没有意义的)。

如果以上情况都不适合您,请使用方法Any()

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

这将在列表中进行枚举,直到找到匹配项或到达末尾为止。


为list.exists使用谓词委托是另一种解决方案,请参阅下文,但是如果您有庞大的列表,并且使用字典的键值将更快,因为它是一个哈希表!享受
道格(Doug)2010年

1
如何检查多个值?
Nitin Karale

79

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

bool alreadyExist = list.Contains(item);

5
这对我没有用,总是说它不存在
Si8

4
@ Si8如果尝试比较对象,则必须确保IEquatable <T> .Equals实现针对对象的类型正确实现。否则,您将不会比较对象的内容。有关如何实现此功能的示例,请参见所指示的包含链接Ahmad。
Doug Knudsen

56

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

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

7

您确定在这种情况下需要列表吗?如果您要在列表中填充许多项目,则使用myList.Contains或会降低性能myList.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实现。您可以覆盖GetHashCode并且Equals在类本身中。


是的,我最喜欢V的布尔值。就此而言,不久之前(大约三周)我无法使用HashSet,因为我正在开发2.0代码,而我放弃了HashSet的Mono实现,因为它是如此有用:)
乔恩·汉纳

4

还要提到的另一点是,您应确保相等性函数符合您的期望。您应该重写equals方法,以设置对象的哪些属性必须匹配才能将两个实例视为相等。

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


3

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

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

请享用!


3

编辑:我首先说:


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


当然,当某些东西也很有价值时,使用它作为键是不明智的。

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


如果对象列表很大,因为它是一个哈希表,并且对于快速查找非常有用,那么我只会使用它。
道格

0

简单但有效

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

要么

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

-1

如果使用EF核心添加

 .UseSerialColumn();

modelBuilder.Entity<JobItem>(entity =>
        {
            entity.ToTable("jobs");

            entity.Property(e => e.Id)
                .HasColumnName("id")
                .UseSerialColumn();
});
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.