简体   繁体   English

如何在两个Inumerable之间使用Any

[英]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. 因此,您不会有任何数据期望单个10移动,并且您不必使应用程序内存混乱。


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 }

Explanation: 说明:

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))

Edit: 编辑:

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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM