使用Linq从其他集中存在密钥的集合中删除?

Rob*_*err 17 c# linq

使用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)));
Run Code Online (Sandbox Code Playgroud)

Roy*_*tus 8

这应该做的伎俩:

var toRemove = banks.Where(x => removeThese.Contains(x.RoutingNumber)).ToList();
var query = banks.RemoveAll(x => toRemove.Contains(x));
Run Code Online (Sandbox Code Playgroud)

第一步是确保无论何时banks更改,您都不必反复重新运行第一个查询.

这也应该有效:

var query = banks.Except(toRemove);
Run Code Online (Sandbox Code Playgroud)

作为你的第二行.

编辑

Tim Schmelter指出,为了Except工作,你需要覆盖EqualsGetHashCode.

所以你可以像这样实现它:

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();
}
Run Code Online (Sandbox Code Playgroud)

  • 您应该检查它们是否具有相同的`RoutingNumber`,因为它似乎是标识符.我也不会在`Equals`和`GetHashCode`中使用`ToString`,因为这可能会在将来发生变化(fe用于调试目的)而你忘记了你也必须在这里更改它.通常,`ToString`与`Equals/GetHashCode`无关.但是你应该首先检查另一个对象是否是"银行",因为这是最重要的. (2认同)

Jam*_*mes 7

一般来说,只需拔出你需要的东西而不是删除那些你不需要的东西就行了

var query = myList.Where(x => !removeThese.Contains(x.RoutingNumber));
Run Code Online (Sandbox Code Playgroud)


Jon*_*Jon 5

通常使用通用LINQ构造来过滤此类型:

banks = banks.Where(bank => !removeThese.Contains(bank.RoutingNumber)).ToList();
Run Code Online (Sandbox Code Playgroud)

在这种特定情况下,您还可以使用List<T>.RemoveAll原位进行过滤,这将更快:

banks.RemoveAll(bank => removeThese.Contains(bank.RoutingNumber));
Run Code Online (Sandbox Code Playgroud)

此外,出于性能原因,如果要删除的路由号码量很大,您应该考虑将它们放入其中HashSet<string>.