18

使用 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)));
4

6 回答 6

9

这应该可以解决问题:

var toRemove = banks.Where(x => removeThese.Contains(x.RoutingNumber)).ToList();
var query = banks.RemoveAll(x => toRemove.Contains(x));

第一步是确保您不必在每次banks更改时一遍又一遍地重新运行第一个查询。

这也应该有效:

var query = banks.Except(toRemove);

作为你的第二行。

编辑

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();
}
于 2013-09-25T09:56:18.467 回答
7

一般来说,只拔出你需要的东西而不是删除你不需要的东西会少一些工作,即

var query = myList.Where(x => !removeThese.Contains(x.RoutingNumber));
于 2013-09-25T09:54:20.967 回答
5

这种类型的过滤通常使用通用 LINQ 结构完成:

banks = banks.Where(bank => !removeThese.Contains(bank.RoutingNumber)).ToList();

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

banks.RemoveAll(bank => removeThese.Contains(bank.RoutingNumber));

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

于 2013-09-25T09:53:46.047 回答
4

要么使用 Linq 扩展方法WhereToList创建一个新列表,要么使用List.RemoveAll更有效的方法,因为它修改了原始列表:

banks = banks.Where(x => !removeThese.Contains(x.RoutingNumber)).ToList();
banks.RemoveAll(x => removeThese.Contains(x.RoutingNumber));

当然,您必须反转条件,因为前者保留Where留下的内容,而后者删除谓词RemoveAll返回的内容。

于 2013-09-25T09:58:44.903 回答
2

你试过使用RemoveAll()吗?

var query = banks.RemoveAll(p => removeThese.Contains(p.RoutingNumber));

这将删除banks匹配记录存在的任何值removeThese

query将包含从列表中删除的记录数。

注意:原始变量banks将由该查询直接更新;不需要重新分配。

于 2013-09-25T09:55:54.973 回答
1

您可以使用 RemoveAll()

var removedIndexes = banks.RemoveAll(x => removeThese.Contains(x.RoutingNumber));

或者

banks = banks.Where(bank => !removeThese.Contains(bank.RoutingNumber)).ToList();
于 2013-09-25T09:57:56.730 回答