[英]How to use Any between two ienumerables
I have the following code inside my asp.net MVC web application: 我的asp.net MVC网络应用程序中包含以下代码:
var currentport = tms.TMSSwitchPorts
.Where(a => a.SwitchID == fromID)
.Select(a2 => a2.PortNumber)
.ToList();
if (currentport.Any(tms.TMSSwitchPorts
.Where(a => a.SwitchID == toID)
.Select(a => a.PortNumber)
.ToList()
)
)
{
// do something
}
but i am unable to use the .Any()
in this way, although i am selecting the PortNumber field in both lists? 但是我无法以这种方式使用
.Any()
,尽管我在两个列表中都选择了PortNumber字段?
Can anyone advise? 有人可以建议吗?
You can to this efficiently and entirely in the database using a simple Join
: 您可以使用简单的
Join
在数据库中高效且完全地做到这一点:
var match = tms.TMSSwitchPorts.Where(a => a.SwitchID == fromID)
.Join(tms.TMSSwitchPorts.Where(a => a.SwitchID == toID),
(a) => a.PortNumber,
(b) => b.PortNumber,
(a, b) => true).Any();
if (match) { ... }
The generated SQL should look like 生成的SQL应该看起来像
SELECT
(CASE
WHEN EXISTS(
SELECT NULL AS [EMPTY]
FROM [TMSSwitchPorts] AS [t0]
INNER JOIN [TMSSwitchPorts] AS [t1] ON [t0].[PortNumber] = [t1].[PortNumber]
WHERE ([t0].[SwitchID] = @p0) AND ([t1].[SwitchID] = @p1)
) THEN 1
ELSE 0
END) AS [value]
so you don't have any data expect a single 1
or 0
moving over the wire and you don't have to clutter up your application memory. 因此,您不会有任何数据期望单个
1
或0
移动,并且您不必使应用程序内存混乱。
The code 编码
if (currentport.Any(tms.TMSSwitchPorts
.Where(a => a.SwitchID == toID)
.Select(a => a.PortNumber)
.ToList()
)
will not work because Any
expects a predicate in the form of Func<T, bool>
, but you pass it a List<Int>
(assuming PortNumber
is an int
). 将不会起作用,因为
Any
希望Func<T, bool>
形式的谓词,但是您将List<Int>
传递给它(假设PortNumber
是一个int
)。
Take the analogous list for SwitchID == toID
. 采取类似的清单
SwitchID == toID
。
var alreadyUsed = tms.TMSSwitchPorts
.Where(a => a.SwitchID == toID)
.Select(a2 => a2.PortNumber)
.ToList();
Then just check that nothing appears in both two lists. 然后只需检查两个列表中均未显示任何内容即可。
if (currentPort.Intersect(alreadyUsed).Any())
{ // do something }
Any()
doesn't work the way you think it does. Any()
不能像您想象的那样工作。 By itself as used above, it checks for any elements in the container. 如上所用,它本身会检查容器中是否有任何元素。 As shown in @BenAaronson's answer (which is slightly better than this answer), it checks if an
IEnumerable
contains any element which for which the function argument returns true. 如@BenAaronson的答案所示(比该答案稍好),它检查
IEnumerable
包含其函数参数返回true的任何元素。
list1.Any(HasSomeProperty)
where HasSomeProperty
is a function which takes an element of list1
and returns a bool; HasSomeProperty
是一个接受list1
元素并返回布尔list1
的函数; or more usually with a lambda: 或更常见的是使用lambda:
list1.Any(x => SomePropertyHoldsFor(x))
I said @BenAaronson's answer was better because it allows some 'short-circuiting' optimizations that I didn't think my solution had. 我说@BenAaronson的答案更好,因为它允许一些我认为我的解决方案没有的“短路”优化。 These are mentioned in the comments to his answer.
在他的回答的评论中提到了这些。 However, with some trial and error I found that Intersect does automatically make the same optimizations - specifically it caches the 'output' of one IEnumerable for comparison with each element of the other, rather than traverse it each time.
但是,通过反复试验,我发现Intersect会自动进行相同的优化-特别是它缓存了一个IEnumerable的“输出”,以便与另一个元素的每个元素进行比较,而不是每次都遍历它。 So my solution is better, as
Intersect
does automatically what you have to think about a little bit for Ben's method ;) @sloth's answer involves a different automatic optimization, and is much is better for the database query using Queryable
that the asker had in mind. 所以我的解决方案更好,因为
Intersect
会自动完成您对Ben方法的思考;)@sloth的答案涉及不同的自动优化,并且对于使用Queryable
进行数据库查询要好得多。
This answer explains how Intersect
works - it is not really 'caching', but it only accesses each IEnumerable
once. 该答案说明了
Intersect
工作原理 -它并不是真正的“缓存”,而是仅访问每个IEnumerable
一次。
Based on jwg's comment, you can check to see if there is a match between the first set of ports (From) and the second set (to), using a Contains
match: 根据jwg的注释,您可以使用
Contains
匹配来检查第一组端口(从)和第二组端口(到)之间是否存在匹配:
var fromPorts = tms.TMSSwitchPorts
.Where(a => a.SwitchID == fromID)
.Select(a2 => a2.PortNumber);
if (tms.TMSSwitchPorts
.Any(a => a.SwitchID == toID &&
fromPorts.Contains(a.PortNumber)))
If your aim is as jwg described in his comment, you could do: 如果您的目标如他的评论中所述,您可以执行以下操作:
var currentportFrom = tms.TMSSwitchPorts
.Where(a => a.SwitchID == fromID)
.Select(a2 => a2.PortNumber)
.ToList();
var currentportTo = tms.TMSSwitchPorts
.Where(a => a.SwitchID == fromID)
.Select(a2 => a2.PortNumber)
.ToList();
if(currentportFrom.Any(cp => currentportTo.Contains(cp))
{
//do something
}
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.