使用另一个列表的内容过滤一个列表

Filtering a List using contents of another List

我有两个列表。我想使用第二个列表中的元素过滤掉第一个列表。所以我有这个代码:

 List<data> dataList = somedata;
 IEnumerable<Filter> filterList  = someFilterData;

然后我使用以下代码进行过滤:

foreach (var s in filterList)
{
     dataList =   dataList .Where(l => l.dataId!= s.Id).ToList();     
}

有人可以建议这是否是一个足够好的方法,或者我们如何使用其他技术使它更好。注意:列表可能会变大,因此我们也在考虑性能。

可能,你需要这个

dataList = dataList.Where(l => !filterList.Select(x => x.Id).Contains(l.dataId)).ToList();

我会这样做,使用哈希集,然后使用单个 Where:

var filtIds = new HashSet<int>(filterList.Select(f=> f.Id));
var filteredDataList = dataList.Where(d=> !filtIds.Contains(d.dataId)).ToArray();

您需要的是只取过滤列表中找不到的这些项目。你可以用 "old school" 的方式,使用循环:

foreach (var listItem in dataList)
{
    foreach (var filterItem in filterList)
    {
        if (listItem == filterItem)
        {
            dataList.Remove(listItem);
            continue;
        }
    }
}

或者您可以使用 LINQ 进行过滤:

dataList.Where(d => filterList.All(f => f.Id != d.dataId))
var filteredQuery =
                from d in dataList
                let filterListIds = from f in filterList
                    select f.Id
                where filterListIds.Contains(d.DataId) == false
                select d;

晚会迟到了,但由于您的过滤器仅被认为是 IEnumerable,因此具体化过滤器以防止在每次迭代时从源中吸取可能不是一个好主意吗?我认为这就是@George 的意思。如果过滤器的源在执行过程中发生变化,则可能会不一致(并且在每次迭代时重新获取它们可能代价高昂):

var filterIds = filterList.Select( f=> f.Id ).ToArray( );

然后,"Not any" 似乎(对我来说)比 "All not equal" 更能表达你的意思。

var results = dataList.Where( d=> !filterIds.Any( f=> d==f ) );

所以基本上您只想从第一个列表中删除出现在第二个列表中的所有内容,并且性能很重要?

我最喜欢,列表越大效率最高。但是 List.RemoveAll 也更有效率:

dataList.RemoveAll(d => filterList.Any(x => x.ID == d.DataID));