对于C#中的alist,是否存在类似于Addrange()的AddUnique方法

时间:2011-12-28 05:49:42

标签: c# collections unique

我在C#中有一个列表:

       var list = new List<Car>();
       list.AddRange(GetGreenCars());
       list.AddRange(GetBigCars());
       list.AddRange(GetSmallCars());

问题是一些相同的汽车在不同的功能中返回,我不希望它们在列表中不止一次。每辆车都有一个唯一的Name属性。无论如何我可以在上面找到这样的东西,但只会添加项目,如果它们是唯一的吗?

9 个答案:

答案 0 :(得分:41)

一种选择是添加它们并删除重复的那些:

var list = new List<Car>();
list.AddRange(GetGreenCars());
list.AddRange(GetBigCars());
list.AddRange(GetSmallCars());
list = list.Distinct().ToList();

答案 1 :(得分:23)

另一种选择是做类似的事情:

public static void AddUnique<T>( this IList<T> self, IEnumerable<T> items )
{
    foreach(var item in items)
        if(!self.Contains(item))
            self.Add(item);
}


var list = new List<Car>();
list.AddUnique(GetGreenCars());
list.AddUnique(GetBigCars());
list.AddUnique(GetSmallCars());

答案 2 :(得分:16)

此处List<T>似乎不合适。您可能需要ISet<T>实施,例如HashSet<T>(或SortedSet<T>,如果您需要订购)。

为了实现这一点,您需要编写一个IEqualityComparer<T>实现,根据Name属性定义汽车之间的相等性。如果这是汽车平等的“规范”定义,您还可以考虑直接将此定义构建到Car类型本身(object.Equalsobject.GetHashCode,并理想地实施IEquatable<T>太)。

答案 3 :(得分:9)

如果您覆盖.Equals()的{​​{1}}方法以确定一个汽车对象与另一个汽车对象相同,那么以下内容应该无需编写扩展方法。

Car

答案 4 :(得分:5)

使用Linq的另一种选择:

public static void AddUnique<T>(this IList<T> self, IEnumerable<T> items)
{
  self.AddRange(
    items.Where(x => self.FirstOrDefault(y => y.Name == x.Name) ==
    null).ToList());
}

var list = new List<Car>();
list.AddUnique(GetGreenCars());
list.AddUnique(GetBigCars());
list.AddUnique(GetSmallCars());

答案 5 :(得分:3)

我创建了一个扩展方法,该方法只为ICollection<T>中实现List<T>(包括IEnumerable<T>)的任何内容添加唯一值。与使用List<T>.Contains()的实现不同,此方法允许您指定lambda表达式,以确定两个项是否相同。

/// <summary>
/// Adds only items that do not exist in source.  May be very slow for large collections and some types of source.
/// </summary>
/// <typeparam name="T">Type in the collection.</typeparam>
/// <param name="source">Source collection</param>
/// <param name="predicate">Predicate to determine whether a new item is already in source.</param>
/// <param name="items">New items.</param>
public static void AddUniqueBy<T>(this ICollection<T> source, Func<T, T, bool> predicate, IEnumerable<T> items)
{
    foreach (T item in items)
    {
        bool existsInSource = source.Where(s => predicate(s, item)).Any();
        if (!existsInSource) source.Add(item);
    }
}

用法:

source.AddUniqueBy<Foo>((s, i) => s.Id == i.Id, items);

答案 6 :(得分:1)

如果程序员不能或不想使用Linq,则有其他选择。

var list = new List<Car>();
list.AddRange(GetGreenCars().FindAll((x) => !list.Contains(x)));
list.AddRange(GetBigCars().FindAll((x) => !list.Contains(x)));
list.AddRange(GetSmallCars().FindAll((x) => !list.Contains(x)));

如果初始列表为空,如上例所示,您实际上可以避免在第一个AddRange()上使用FindAll(...)。

答案 7 :(得分:0)

如果你想比较一个属性(在这种情况下为id),这应该可以工作

var list = new List<string>();
list.AddRange(GetGreenCars().Where(greencar => !list.Contains(greencar, car => car.id == greencar.id)));
list.AddRange(GetBigCars().Where(bigcar => !list.Contains(bigcar, car => car.id == bigcar.id)));
list.AddRange(GetSmallCars().Where(smallcar => !list.Contains(smallcar, car => car.id == smallcar.id)));

答案 8 :(得分:0)

假设您的Get * Cars()返回汽车列表,另一个选择可能是:

var list = new List<Car>();
GetGreenCars().ForEach(c => { if (!list.Contains(c)) list.Add(c); });
GetBigCars().ForEach(c => { if (!list.Contains(c)) list.Add(c); });
GetSmallCars().ForEach(c => { if (!list.Contains(c)) list.Add(c); });
相关问题