使用LINQ选择集合中每个项目的列表,除非该项目存在于另一个集合中
本文关键字:项目 集合 另一个 存在 选择 LINQ 使用 列表 | 更新日期: 2023-09-27 17:50:03
这是可行的,但不仅看起来很糟糕,而且似乎效率也不高(我还没有评估性能,因为我知道一定有更好的方法)。
public IEnumerable<Observation> AvailableObservations
{
get
{
foreach (var observation in db.Observations)
{
if (Observations.Any(x => x.Id == observation.Id))
{
}
else
{
yield return observation;
}
}
}
}
本质上,我想要列表db.Observations
中的所有内容(通过EF6从db中提取)并删除当前在this.Observations
中选择的所有条目,这是ICollection<Observations>
我已经尝试使用。except (this.Observations),但得到一个错误,我认为可能与使用except与IEnumerable实体上的iccollection有关。
任何可以去除foreach
循环的东西都是一个好的开始。
你的循环相当于:
return db.Observations.Where(o => !Observations.Any(oo => oo.Id == o.Id));
但这并不比你现有的效率高。
一个更有效的方法是创建一个id的HashSet并从中过滤:
HashSet<int> ids = new HashSet<int>(Observations.Select(o => o.Id));
return db.Observations.Where(o => !ids.Contains(o.Id));
这样,你只遍历主列表一次,以创建一个可以在O(1)时间内搜索的HashSet
。
这里可以做两个优化:
- 限制从数据库中获取的观测值的数量
- 使所选观测id的查找更快
当前实现的复杂度为O(N * M)
,其中N
是db.Observations
中的项数,M
是this.Observations
中的项数。
首先创建this.Observations
:
HashSet
,这将有助于提高性能。var observationIds = new HashSet<int>(this.Observations.Select(x => x.Id));
这将允许您快速查找id。
与where子句(使用LINQ的Where()
)结合使用可以得到一个有效的查询:
public IEnumerable<Observation> AvailableObservations
{
get
{
var observationIds = new HashSet<int>(this.Observations.Select(x => x.Id));
return db.Observations.Where(x => !observationIds.Contains(x.Id));
}
}