谁有一个快速的方法去重复在c#的泛型列表?


当前回答

David J。的答案是一个很好的方法,不需要额外的对象,排序等。但是,它可以在以下方面进行改进:

for (int innerIndex = items.计数 - 1;内索引 > 外索引 ;内部索引--)

因此,对于整个列表,外部循环会从上到下,但内部循环会从下到“直到到达外部循环的位置”。

外部循环确保整个列表被处理,内部循环找到实际的重复项,这些只会发生在外部循环还没有处理的部分。

或者如果你不想对内循环做自底向上你可以让内循环从outerIndex + 1开始。

其他回答

如果你有两个类Product和Customer,我们想从它们的列表中删除重复的项

public class Product
{
    public int Id { get; set; }
    public string ProductName { get; set; }
}

public class Customer
{
    public int Id { get; set; }
    public string CustomerName { get; set; }

}

您必须在下面的表单中定义一个泛型类

public class ItemEqualityComparer<T> : IEqualityComparer<T> where T : class
{
    private readonly PropertyInfo _propertyInfo;

    public ItemEqualityComparer(string keyItem)
    {
        _propertyInfo = typeof(T).GetProperty(keyItem, BindingFlags.GetProperty | BindingFlags.Instance | BindingFlags.Public);
    }

    public bool Equals(T x, T y)
    {
        var xValue = _propertyInfo?.GetValue(x, null);
        var yValue = _propertyInfo?.GetValue(y, null);
        return xValue != null && yValue != null && xValue.Equals(yValue);
    }

    public int GetHashCode(T obj)
    {
        var propertyValue = _propertyInfo.GetValue(obj, null);
        return propertyValue == null ? 0 : propertyValue.GetHashCode();
    }
}

然后,你可以删除列表中重复的项目。

var products = new List<Product>
            {
                new Product{ProductName = "product 1" ,Id = 1,},
                new Product{ProductName = "product 2" ,Id = 2,},
                new Product{ProductName = "product 2" ,Id = 4,},
                new Product{ProductName = "product 2" ,Id = 4,},
            };
var productList = products.Distinct(new ItemEqualityComparer<Product>(nameof(Product.Id))).ToList();

var customers = new List<Customer>
            {
                new Customer{CustomerName = "Customer 1" ,Id = 5,},
                new Customer{CustomerName = "Customer 2" ,Id = 5,},
                new Customer{CustomerName = "Customer 2" ,Id = 5,},
                new Customer{CustomerName = "Customer 2" ,Id = 5,},
            };
var customerList = customers.Distinct(new ItemEqualityComparer<Customer>(nameof(Customer.Id))).ToList();

这段代码通过Id删除重复项,如果你想通过其他属性删除重复项,你可以更改名称(YourClass.DuplicateProperty)和名称(Customer.CustomerName),然后通过CustomerName属性删除重复项。

如果你不关心顺序,你可以把这些项推到HashSet中,如果你想保持顺序,你可以这样做:

var unique = new List<T>();
var hs = new HashSet<T>();
foreach (T t in list)
    if (hs.Add(t))
        unique.Add(t);

或者用Linq的方式:

var hs = new HashSet<T>();
list.All( x =>  hs.Add(x) );

编辑:HashSet方法是O(N)时间和O(N)空间,而排序,然后使唯一(由@lassevk和其他人建议)是O(N*lgN)时间和O(1)空间,所以我不太清楚(因为它是第一眼),排序方式是较差的

把它排序,然后检查两个和两个相邻的,因为重复的会聚集在一起。

就像这样:

list.Sort();
Int32 index = list.Count - 1;
while (index > 0)
{
    if (list[index] == list[index - 1])
    {
        if (index < list.Count - 1)
            (list[index], list[list.Count - 1]) = (list[list.Count - 1], list[index]);
        list.RemoveAt(list.Count - 1);
        index--;
    }
    else
        index--;
}

注:

从后到前进行比较,避免每次移除后都要列出度假胜地列表 这个例子现在使用c#值元组来进行交换,如果你不能使用它,可以用适当的代码来代替 最终结果不再排序

使用HashSet: list = new HashSet<T>(list).ToList();

如何:

var noDupes = list.Distinct().ToList();

在。net 3.5?