如何在两个ienumebles之间使用任何

时间:2014-05-22 11:59:24

标签: c# linq entity-framework asp.net-mvc-4

我的asp.net MVC Web应用程序中包含以下代码:

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
            }

但我无法以这种方式使用.Any(),虽然我在两个列表中都选择了PortNumber字段?

有人可以提供建议吗?

4 个答案:

答案 0 :(得分:4)

您可以使用简单的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) { ... }

生成的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]

所以,如果您没有任何数据需要单个10移动电话,那么您就不必弄乱应用程序内存。


代码

if (currentport.Any(tms.TMSSwitchPorts
                               .Where(a => a.SwitchID == toID)
                               .Select(a => a.PortNumber)
                               .ToList()
                           )

不起作用,因为Any期望Func<T, bool>形式的谓词,但是您传递List<Int>(假设PortNumberint

答案 1 :(得分:1)

SwitchID == toID的类似列表。

var alreadyUsed = tms.TMSSwitchPorts
                     .Where(a => a.SwitchID == toID)
                     .Select(a2 => a2.PortNumber)
                     .ToList();

然后检查两个列表中是否都没有出现。

if (currentPort.Intersect(alreadyUsed).Any())
{ // do something }

说明:

Any()并不像您认为的那样工作。如上所述,它本身检查容器中的任何元素。如@ BenAaronson的答案(比这个答案稍好一点)所示,它检查IEnumerable是否包含函数参数返回true的任何元素。

list1.Any(HasSomeProperty)

其中HasSomeProperty是一个函数,它接受list1的元素并返回一个bool;或更多通常使用lambda:

list1.Any(x => SomePropertyHoldsFor(x))

编辑:

我说@ BenAaronson的回答更好,因为它允许一些短路&#39;优化,我没有想到我的解决方案。这些在他的回答的评论中提到。但是,通过一些反复试验,我发现Intersect会自动进行相同的优化 - 特别是它会缓存&#39;输出&#39;一个IEnumerable用于与另一个元素的每个元素进行比较,而不是每次遍历它。所以我的解决方案更好,因为Intersect会自动为你的方法做一些思考; @懒惰的答案涉及不同的自动优化,并且更好对于使用Queryable的数据库查询,请问者想到了。

This answer explains how Intersect works - 它实际上不是“缓存”,但它只访问每个IEnumerable一次。

答案 2 :(得分:1)

根据jwg的评论,您可以使用Contains匹配检查第一组端口(From)和第二组(to)之间是否匹配:

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

答案 3 :(得分:0)

如果你的目标是他的评论中描述的jwg,你可以这样做:

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
}