在列表中选择存在于(A、B、C)中的对象的Linq查询

228

我有一个名为orders的列表。
我希望基于一组订单状态来选择orders

因此本质上是select orders where order.StatusCode in ("A", "B", "C")

// Filter the orders based on the order status
var filteredOrders = from order in orders.Order
                     where order.StatusCode.????????("A", "B", "C")
                     select order;

感谢所有快速回答的人,特别是关于lambda解决方案的。我还没有使用过lambda表达式做过任何事情。我认为我可以使用(o => !(statuses.Contains(o.OrderHeaderOrderStatusCode)))来进行NOT包含操作。 - MartinS
5个回答

365

你的状态码也是一个集合,因此使用Contains

var allowedStatus = new[]{ "A", "B", "C" };
var filteredOrders = orders.Order.Where(o => allowedStatus.Contains(o.StatusCode));

或者在查询语法中:

var filteredOrders = from order in orders.Order
                     where allowedStatus.Contains(order.StatusCode)
                     select order;

2
我建议使用HashSet而不是数组来存储allowedStatus,因为HashSet的contains方法最快。如果数组中包含超过1000个项,则会出现性能问题。 var allowedStatus = new HashSet<string> { "A", "B", "C" }; - Jay Shah
@JayShah: 回答晚了:通常情况下你是对的,如果有成千上万的项,最好一开始就使用HashSet<T>。但这不总是一个好主意:如果你传入的已经是一个数组或列表,那么你需要另一个集合,也就需要更多的内存;你需要填充那个HashSet<T>,因此需要更多的CPU周期;如果这不是Linq-To-Objects而是Linq-To-Entities(其中Contains被转换为SQL中的IN子句,它具有限制条件),那么你可能无法使用数千个项。 - Tim Schmelter
@JayShah 同时,这不会改变使用实体框架时的性能。它将被转换为 SQL 的 "IN" 子句,并由数据库引擎执行。在这种情况下,数组创建速度会略快一些。 - Guilherme

26
NB: 这是针对对象的LINQ,我不确定它是否适用于实体的LINQ,并且现在没有时间进行检查。实际上,将其翻译成x在[A,B,C]中并不太困难,但您必须自己检查。

因此,您可以使用 Any 来替换代码中的 ???? ,这更符合 LINQ 的语法:

// Filter the orders based on the order status
var filteredOrders = from order in orders.Order
                     where new[] { "A", "B", "C" }.Any(s => s == order.StatusCode)
                     select order;

这与您从SQL中了解的相反,这就是为什么它不太明显的原因。

当然,如果您更喜欢流畅的语法,这里有:

var filteredOrders = orders.Order.Where(order => new[] {"A", "B", "C"}.Any(s => s == order.StatusCode));

在这里,我们再次看到了LINQ的一个惊喜(就像将select放在最后的Joda语言)。然而,从某种意义上讲,它是相当合乎逻辑的,因为它检查列表(集合)中是否有至少一个项目(即任何),匹配单个值。


19
var statuses = new[] { "A", "B", "C" };

var filteredOrders = from order in orders.Order
                             where statuses.Contains(order.StatusCode)
                             select order;

18

使用Contains函数进行尝试;

确定序列是否包含指定的元素。

var allowedStatus = new[]{ "A", "B", "C" };
var filteredOrders = orders.Order.Where(o => allowedStatus.Contains(o.StatusCode));

-4

要注意了,.Contains()会匹配任何包含在字符串中的子串,包括你不想要的字符串。例如,new[] { "A", "B", "AA" }.Contains("A")将返回A和AA,这可能不是你想要的结果。我曾经就因为这个问题被坑过。

.Any()或者.Exists()是更安全的选择。


new[] { "B", "AA" }.Contains("A") 将返回 false,而不是 true。 - Jay Shah

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接