C#:比较自定义类的两个ArrayList并查找重复项

时间:2016-09-12 19:14:11

标签: c# arrays linq arraylist duplicates

我有两个ArrayList数组。

public class ProductDetails
{
    public string id;
    public string description;
    public float rate;
}

ArrayList products1 = new ArrayList();
ArrayList products2 = new ArrayList();
ArrayList duplicateProducts = new ArrayList();

现在我想要的是让所有产品(包含ProductDetails类的所有字段)在products1products2中都有重复的描述。

我可以像传统方式一样运行两个for / while循环,但如果我在两个数组中拥有超过10k个元素,这将非常慢。

所以可能用LINQ做了一些事情。

3 个答案:

答案 0 :(得分:1)

如果你想使用linQ,你需要编写自己的EqualityComparer,你可以覆盖两个方法 Equals GetHashCode()

 public class ProductDetails
    { 
        public string id {get; set;}
        public string description {get; set;}
        public float rate {get; set;}
    }

public class ProductComparer : IEqualityComparer<ProductDetails>
{

    public bool Equals(ProductDetails x, ProductDetails y)
    {
        //Check whether the objects are the same object. 
        if (Object.ReferenceEquals(x, y)) return true;

        //Check whether the products' properties are equal. 
        return x != null && y != null && x.id.Equals(y.id) && x.description.Equals(y.description);
    }

    public int GetHashCode(ProductDetails obj)
    {
        //Get hash code for the description field if it is not null. 
        int hashProductDesc = obj.description == null ? 0 : obj.description.GetHashCode();

        //Get hash code for the idfield. 
        int hashProductId = obj.id.GetHashCode();

        //Calculate the hash code for the product. 
        return hashProductDesc ^ hashProductId ;
    }
}

现在,假设你有这个对象:

ProductDetails [] items1= { new ProductDetails { description= "aa", id= 9, rating=2.0f }, 
                       new ProductDetails { description= "b", id= 4, rating=2.0f} };

ProductDetails [] items= { new ProductDetails { description= "aa", id= 9, rating=1.0f }, 
                       new ProductDetails { description= "c", id= 12, rating=2.0f } };


IEnumerable<ProductDetails> duplicates =
    items1.Intersect(items2, new ProductComparer());

答案 1 :(得分:0)

考虑重写 System.Object.Equals 方法。

   public class ProductDetails
   {
     public string id;
     public string description;
     public float rate;

     public override bool Equals(object obj)
     {
       if(obj is ProductDetails == null)
          return false;

      if(ReferenceEquals(obj,this))
          return true;

       ProductDetails p = (ProductDetails)obj;
       return description == p.description;
    }
  }

过滤将如此简单:

var result = products1.Where(product=>products2.Contains(product));

编辑:

请考虑此实施不是最佳的。

此外 - 在您的问题的评论中已经提出您使用数据库 这样就可以优化性能 - 根据数据库实现 - 在任何情况下 - 开销都不是你的。

但是,您可以使用Dictionary或HashSet优化此代码:
重载 System.Object.GetHashCode 方法:

public override int GetHashCode()
{
  return description.GetHashCode();
}

您现在可以执行此操作:

var hashSet = new HashSet<ProductDetails>(products1);
var result = products2.Where(product=>hashSet.Contains(product));

这将提高您的性能,因为查找成本更低。

答案 2 :(得分:-1)

10k元素没什么,但请确保使用正确的集合类型。 ArrayList已被弃用,请使用List<ProductDetails>

下一步是为您的班级实施适当的EqualsGetHashCode覆盖。这里假设description是关键,因为从重复的角度来看,你关心的是:

public class ProductDetails
{
    public string id;
    public string description;
    public float rate;

    public override bool Equals(object obj)
    {
        var p = obj as ProductDetails;
        return ReferenceEquals(p, null) ? false : description == obj.description;
    }

    public override int GetHashCode() => description.GetHashCode();    
}

现在我们有选择权。一种简单有效的方法是使用哈希集:

var set = new HashSet<ProductDetails>();
var products1 = new List<ProductDetails>();  // fill it
var products2 = new List<ProductDetails>();  // fill it

// shove everything in the first list in the set
foreach(var item in products1)
    set.Add(item);

// and simply test the elements in the second set
foreach(var item in products2)
    if(set.Contains(item))
    {
        // item.description was already used in products1, handle it here
    }

这为您提供线性(O(n))时间复杂度,您可以获得最佳效果。