使用 Linq 从其他集中存在键的集合中删除
本文关键字:集合 删除 存在 Linq 其他 集中 使用 | 更新日期: 2023-09-27 18:32:40
使用 Linq 进行设置减法的正确方法是什么? 我有一个8000 +银行的列表,我想根据路由号码删除其中的一部分。 该部分位于另一个列表中,路由号码是两者的键属性。 这是一个简化:
public class Bank
{
public string RoutingNumber { get; set; }
public string Name { get; set; }
}
var removeThese = new List<string>() { "111", "444", "777" };
var banks = new List<Bank>()
{
new Bank() { RoutingNumber = "111", Name = "First Federal" },
new Bank() { RoutingNumber = "222", Name = "Second Federal" },
new Bank() { RoutingNumber = "333", Name = "Third Federal" },
new Bank() { RoutingNumber = "444", Name = "Fourth Federal" },
new Bank() { RoutingNumber = "555", Name = "Fifth Federal" },
new Bank() { RoutingNumber = "666", Name = "Sixth Federal" },
new Bank() { RoutingNumber = "777", Name = "Seventh Federal" },
new Bank() { RoutingNumber = "888", Name = "Eight Federal" },
new Bank() { RoutingNumber = "999", Name = "Ninth Federal" },
};
var query = banks.Remove(banks.Where(x => removeThese.Contains(x.RoutingNumber)));
这应该可以解决问题:
var toRemove = banks.Where(x => removeThese.Contains(x.RoutingNumber)).ToList();
var query = banks.RemoveAll(x => toRemove.Contains(x));
第一步是确保不必在更改时一遍又一遍地重新运行第一个查询banks
。
这也应该有效:
var query = banks.Except(toRemove);
作为您的第二行。
编辑
蒂姆·施梅特指出,要使Except
起作用,您需要覆盖Equals
和GetHashCode
。
所以你可以像这样实现它:
public override string ToString()
{
... any serialization will do, for instance JSON or CSV or XML ...
... OR any serialization that identifies the object quickly, such as:
return "Bank: " + this.RoutingNumber;
}
public override bool Equals(System.Object obj)
{
return ((obj is Bank) && (this.ToString().Equals(obj.ToString()));
}
public override int GetHashCode()
{
return this.ToString().GetHashCode();
}
一般来说,只提取你需要的而不是删除你不需要的那些
,即var query = myList.Where(x => !removeThese.Contains(x.RoutingNumber));
这种类型的筛选通常使用泛型 LINQ 构造完成:
banks = banks.Where(bank => !removeThese.Contains(bank.RoutingNumber)).ToList();
在这种特定情况下,您还可以使用 List<T>.RemoveAll
就地执行筛选,这将更快:
banks.RemoveAll(bank => removeThese.Contains(bank.RoutingNumber));
此外,出于性能原因,如果要删除的路由号码数量很大,则应考虑将它们放入HashSet<string>
中。
要么使用
Linq 扩展方法Where
和ToList
创建新列表,要么使用 List.RemoveAll
更有效,因为它会修改原始列表:
banks = banks.Where(x => !removeThese.Contains(x.RoutingNumber)).ToList();
banks.RemoveAll(x => removeThese.Contains(x.RoutingNumber));
当然,你必须颠倒条件,因为前者保留Where
留下的东西,而后者删除RemoveAll
返回的谓词。
你试过使用 RemoveAll()
吗?
var query = banks.RemoveAll(p => removeThese.Contains(p.RoutingNumber));
这将从banks
中删除removeThese
中存在匹配记录的任何值。
query
将包含从列表中删除的记录数。
注意:原始变量banks
将直接通过此查询更新;不需要重新分配。
你可以使用 RemoveAll()
var removedIndexes = banks.RemoveAll(x => removeThese.Contains(x.RoutingNumber));
或
banks = banks.Where(bank => !removeThese.Contains(bank.RoutingNumber)).ToList();