【问题标题】:Checking if same object is already present in a list检查列表中是否已经存在相同的对象
【发布时间】:2009-08-10 11:41:05
【问题描述】:

故事如下:

我正在尝试列出不同集群...我只想拥有必要的集群...并且集群可以相同。

如何通过检查列表是否包含对象来将其添加到列表中(我知道对象不能在此处传递)

这是我的示例报价:

foreach (Cluster cluster in clustersByProgramme)
{
    if (!clusterList.Contains(cluster))
    {
        clusterList.Add(cluster);
    }
}

【问题讨论】:

    标签: c# list


    【解决方案1】:

    您的代码应该可以工作;如果没有,您可能正在使用代表相同实际集群的不同 对象实例,并且您可能没有提供合适的 Equals 实现(您还应该更新 GetHashCode 在同一时间)。

    另外 - 在 .NET 3.5 中,这可能很简单:

    var clusterList = clustersByProgramme.Distinct().ToList();
    

    作为支持相等测试的类示例:

    class Cluster // possibly also IEquatable<Cluster>
    {
        public string Name { get { return name; } }
        private readonly string name;
        public Cluster(string name) { this.name = name ?? ""; }
        public override string ToString() { return Name; }
        public override int GetHashCode() { return Name.GetHashCode(); }
        public override bool Equals(object obj)
        {
            Cluster other = obj as Cluster;
            return obj == null ? false : this.Name == other.Name;
        }
    }
    

    【讨论】:

    • 将 name 字段设置为只读的奖励,这是重新实现 GetHashCode() 的正确方法,而世界不会炸毁;)
    • @Pop- 是的,不可变字段是 GetHashCode() 的方法。
    • 抱歉 - 不喜欢 name ?? "" - 改为抛出异常。
    • @Eric- 实际上,这是一个选项 (ArgumentNullException)。我会诚实的;在这个例子中主要是为了安全空间......
    • 如果问题是“我还是应该通过一个属性,还是应该只使用一个字段”,那么请注意 JIT 几乎肯定会“内联”一个基本的“返回字段”; getter - 所以没有显着差异。除了如果您稍后更改内容,访问该属性会更加灵活。
    【解决方案2】:

    您的示例非常简单。我唯一可以推荐的是你使用Exists 方法:

    谓词是一个代表 如果对象返回 true 的方法 传递给它的条件匹配 在委托中定义。要素 当前列表的单独 传递给谓词委托,和 匹配时停止处理 找到了。

    此方法执行线性搜索; 因此,这种方法是 O(n) 运算,其中 n 是计数。

    【讨论】:

      【解决方案3】:

      如果您使用的是 .NET 3.5,请使用 HashSet 来执行此操作。

      HashSet<Cluster> clusterList = new HashSet<Cluster>();
      foreach (Cluster cluster in clustersByProgramme)
      {
           clusterList.Add(cluster);
      }
      

      在这种情况下,还要确保如果 cluster1 == cluster2,那么

      cluster1.Equals(cluster2);
      cluster2.Equals(cluster1); //yeah, could be different depending on your impl
      cluster1.GetHashCode() == cluster2.GetHashCode();
      

      【讨论】:

      • A HashSet&lt;T&gt; 不起作用 - OP 的列表可以包含重复项,而不是某些重复项。
      • 除非我误读了要求,我不认为我是。
      • 是的,重新阅读需求,看起来他正在创建一个新的、独特的列表。在这种情况下, HashSet 将是最好的选择,假设不需要排序。
      【解决方案4】:

      您的代码是正确的,但效率不高。您可以改为使用 HashSet&lt;T&gt;,如下所示:

      HashSet<Cluster> clusterSet = new HashSet<T>();
      foreach (Cluster cluster in clustersByProgramme)
        clusterSet.Add(cluster);
      

      在这种情况下,还要确保如果 cluster1 == cluster2,那么

      cluster1.Equals(cluster2);
      cluster2.Equals(cluster1); //yeah, could be different depending on your impl
      cluster1.GetHashCode() == cluster2.GetHashCode();
      

      【讨论】:

        【解决方案5】:

        为什么不直接使用字典?

        只要您的项目具有良好的哈希值,它就是 n(1)。

        似乎是一个简单的解决方案

        即dictionary.Contains(key)是n(1)

        然后您可以更新现有的(如果有的话)或添加新的

        【讨论】:

          猜你喜欢
          • 2012-09-26
          • 1970-01-01
          • 2011-09-11
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2017-02-24
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多