我有两个收藏品
List<Car> currentCars = GetCurrentCars();
List<Car> newCars = GetNewCars();
我不想使用foreach循环或其他东西,因为我认为应该有更好的方法来做到这一点。
我正在寻找更有效的方法来比较这些集合并获得结果:
类型Car具有int属性Id。
有一个答案,已经删除了说 我的意思是说效率更高:更少的代码,更少的机制和更具可读性的案例
所以这样思考我的情况是什么?
什么是更少的代码,更少的机制,更可读的案例?
答案 0 :(得分:13)
你可以这样做:
// 1) List of cars in newCars and not in currentCars
var newButNotCurrentCars = newCars.Except(currentCars);
// 2) List of cars in currentCars and not in newCars
var currentButNotNewCars = currentCars.Except(newCars);
该代码使用Enumerable.Except扩展方法(在.Net 3.5及更高版本中提供)。
我相信这符合您的“更少代码,更少机制和更易读”的标准。
答案 1 :(得分:11)
您可以使用Except
:
var currentCarsNotInNewCars = currentCars.Except(newCars);
var newCarsNotInCurrentCars = newCars.Except(currentCars);
但是这比foreach
解决方案没有性能优势。它看起来更干净
另外,请注意,您需要为IEquatable<T>
类实现Car
,因此需要对ID进行比较,而不是在引用上进行比较。
从绩效方面来说,更好的方法是不使用List<T>
而使用Dictionary<TKey, TValue>
并将ID作为关键字:
var currentCarsDictionary = currentCars.ToDictionary(x => x.ID);
var newCarsDictionary = newCars.ToDictionary(x => x.ID);
var currentCarsNotInNewCars =
currentCarsDictionary.Where(x => !newCarsDictionary.ContainsKey(x.Key))
.Select(x => x.Value);
var newCarsNotInCurrentCars =
newCarsDictionary.Where(x => !currentCarsDictionary.ContainsKey(x.Key))
.Select(x => x.Value);
答案 2 :(得分:3)
如果您从HashSet
开始,可以使用Except
方法。
HashSet<Car> currentCars = GetCurrentCars();
HashSet<Car> newCars = GetNewCars();
currentCars.Except(newCars);
newCars.Except(currentCars);
w / set比列表快得多。 (在引擎盖下,列表只是做一个foreach,可以优化集合。)
答案 3 :(得分:2)
我会覆盖Equals
的{{1}}以按ID进行比较,然后您可以使用Car
扩展方法。如果您无法覆盖IEnumerable.Except
,则可以创建自己的Equals
,按ID对比两辆车。
IEqualityComparer<Car>
答案 4 :(得分:2)
您可以使用LINQ ...
List<Car> currentCars = new List<Car>();
List<Car> newCars = new List<Car>();
List<Car> currentButNotNew = currentCars.Where(c => !newCars.Contains(c)).ToList();
List<Car> newButNotCurrent = newCars.Where(c => !currentCars.Contains(c)).ToList();
......但不要被愚弄。它可能对你来说代码较少,但肯定会有某些for循环
编辑:没有意识到有一种Except方法:(答案 5 :(得分:1)
如果您正在寻找效率,请在Cars上实施IComparable(对您的唯一ID进行排序)并使用SortedList。然后,您可以一起浏览您的收藏,并在O(n)中评估您的支票。当然,这会增加List插入的成本,以维持排序的性质。
答案 6 :(得分:0)
您可以将较小的列表复制到基于哈希表的集合(如HashSet或Dictionary)中,然后迭代第二个列表并检查该项是否存在于哈希表中。
这将减少从foreach案例中的朴素foreach中的O(N ^ 2)到O(N)的时间。
这是您在不了解更多关于列表的情况下可以做的最好的事情(例如,如果对列表进行排序,您可以更好地执行 little ,但是,因为您必须“触摸”每辆车至少检查一次,看看它是否在新车清单上,你永远做不到O(N)
答案 7 :(得分:0)
如果比较Id属性就足以说明Car是否等于另一个,为了避免某种循环,你可以用自己的类覆盖List,跟踪项目并使用整个集合上的IEqualityComparer
,如下所示:
class CarComparer : IList<Car>, IEquatable<CarComparer>
{
public bool Equals(CarComparer other)
{
return object.Equals(GetHashCode(),other.GetHashCode());
}
public override int GetHashCode()
{
return _runningHash;
}
public void Insert(int index, Car item)
{
// Update _runningHash here
throw new NotImplementedException();
}
public void RemoveAt(int index)
{
// Update _runningHash here
throw new NotImplementedException();
}
// More IList<Car> Overrides ....
}
然后,您只需要覆盖Add
,Remove
等以及可能影响列表中项目的任何其他方法。然后,您可以保留一个私有变量,该变量是列表中某些项目的哈希值。覆盖Equals
方法时,您可以只比较这个私有变量。到目前为止,这不是最干净的方法(因为你必须跟上你的哈希变量),但这将导致你不必循环进行比较。如果是我,我会像其他人在这里提到的那样使用Linq ......