使用Where()foreach返回从多个源返回第一个项目

时间:2014-10-24 06:52:33

标签: c# linq

我找到了一个有趣的代码片段,它使用Where()和foreach以非预期的方式。但是,它们的使用似乎是一个非常有趣的解决方案,可以显着减少代码行。

// a, b, c are IEnumerable<string> of any data source and could be expensive to iterate
string GetFirstString(){

    foreach( var str in a.Where(...) )
        return str;

    foreach( var str in b.Where(...) )
        return str;

    foreach( var str in c.Where(...) )
        return str;

    return "";

} 

有没有更好的方法做到这一点同样短,但不“滥用”Where和foreach?

更新:

如果任何列表包含空条目且Where谓词允许空条目通过,则可能有错误,然后它将返回null。 (在大多数情况下,GetFirstString应该跳过空值)

5 个答案:

答案 0 :(得分:3)

试试这个:

string GetFirstString(){
    return a.FirstOrDefault(...) 
        ?? b.FirstOrDefault(...) 
        ?? c.FirstOrDefault(...)
        ?? "";
}

答案 1 :(得分:1)

您可以使用Concat将所有内容加入单个序列,然后选择First

var list = a.Where(...)
           .Concat(b.Where(...))
           .Concat(c.Where(..))
           .Take(1)
           .ToList();//Make sure we execute the query only once.

if(list.Count > 0)
    return list[0];

return "";

注意:您可以认为Take(1)ToList并返回列表中的第一个元素似乎是多余的,您可以将其更改为FirstOrDefault。但这改变了代码的语义。问题是当您的过滤序列包含null时,FirstOrDefault() ?? ""将返回空字符串,但OP的原始代码将返回null

答案 2 :(得分:1)

string GetFirstString(){

    var str = "";

    if( str == null )
        str = b.FirstOrDefault(...);

    if( str == null )
        str = b.FirstOrDefault(...);

    if( str == null )
        str = c.FirstOrDefault(...);

    return str;
} 

这对我来说似乎很难看,因为它引入了一个变量并改变了方法的整个结构。

答案 3 :(得分:0)

使用FirstOrDefault()而不是First()

string GetFirstString(){

        if (a.Any(...))
           return a.FirstOrDefault(...);

        if (b.Any(...))
           return b.FirstOrDefault(...);

        if (c.Any(...))
           return c.FirstOrDefault(...);

        return "";

    } 

答案 4 :(得分:-1)

您可以使用Union扩展方法

string GetFirstString()
{
    return a.Where(...)
        .Union(b.Where(...))
        .Union(c.Where(...)).FirstOrDefault();
}