2016-11-30 41 views
1

我有以下代码:合理性检查:这些嵌套的。所有调用都等同于LINQ中相应的.Where和.SelectMany调用吗?

bool b = myList 
    .SelectMany(x => x.MyList) 
    .Where(x => x.MyBool) 
    .SelectMany(x => x.MyList) 
    .All(x => x.MyBool) 

我想是的,但我的同事向我挑战,这一变化可能在某些功能上的不同:

bool b = myList 
    .All(x => x.MyList 
     .Where(y => y.MyBool) 
     .All(y => y.MyList 
      .All(z => z.MyBool))) 

到这是功能上等同情况(例如,如果任何集合是空的,例如)。

虽然答案是肯定或否定,但对于可读性,圈复杂度,时间复杂度和性能方面哪一个更好,也会有所了解。

UPDATE:

所以,我用异型的代码如下:

static void Main(string[] args) 
{ 
    var myList = new List<A>(); 

    for (var j = 0; j < 1000; j++) 
    { 
     var a = new A(); 

     for (var k = 0; k < 1000; k++) 
     { 
      var b = new B {MyBool = true}; 

      for (var l = 0; l < 1000; l++) 
      { 
       var c = new C {MyBool = true}; 
       b.MyList.Add(c); 
      } 

      a.MyList.Add(b); 
     } 

     myList.Add(a); 
    } 

    for (var x = 0; x < 10000; x++) 
    { 
     bool b1 = Foo(myList); 
    } 

    for (var x = 0; x < 10000; x++) 
    { 
     bool b2 = Bar(myList); 
    } 
} 

private static bool Foo(List<A> myList) 
{ 
    return myList 
     .All(x => x.MyList 
      .Where(y => y.MyBool) 
      .All(y => y.MyList 
       .All(z => z.MyBool))); 
} 

private static bool Bar(List<A> myList) 
{ 
    return myList 
     .SelectMany(x => x.MyList) 
     .Where(x => x.MyBool) 
     .SelectMany(x => x.MyList) 
     .All(x => x.MyBool); 
} 

private class A 
{ 
    public List<B> MyList => new List<B>(); 
} 

private class B 
{ 
    public bool MyBool { get; set; } 

    public List<C> MyList => new List<C>(); 
} 

private class C 
{ 
    public bool MyBool { get; set; } 
} 

我发现的是,使用.SelectMany.Where第二种方法(Bar)比快了近80%第一种方法(Foo)使用嵌套.All调用。但是这只能在一个非常大的数据集上证明,实际所花的时间非常短。如果每个元素调用一个花费较长时间的查询(例如,到一个数据库),如果实际上性能差异是由于元素被读取的次数所致,那么这对于较小数据集可能更重要。但是,如果差异是由读取元素之间的开销引起的,并且对于任一方法读取元素的次数相同,则我认为无论数据集大小或元素读取时间如何,性能差异总是可以忽略的。

结果如下(从Visual Studio性能分析器): enter image description here

+1

既然'All'对空集返回'true',它们是等价的。什么更好,它是基于意见还是具体实施。 –

回答

4
myList.All // is it true for all elements in myList that… 
(x => x.MyList //in their MyList property 
.Where(y => y.MyBool) // those elements that have MyBool returning true 
.All(// have it true for all elements in that list that… 
y => y.MyList //in their MyList property 
.All(z => z.MyBool) // all elements have MyBool returning true 


myList.SelectMany(// for all the elements in myList 
x => x.MyList) // for all elements in their MyList property… 
.Where(x => x.MyBool) // that have MyBool returning true 
.SelectMany(// for all those elements 
x => x.MyList) // for all elements in their MyList property 
.All(x => x.MyBool) // is it true that all elements have MyBool returning true 

所以,是的,他们具有相同的含义。特别是在任何情况下,在任何阶段的空列表意味着来自All()方法的true,来自空虚的true是否传递到呼叫All()或空虚传递到最终的All()

可读性是一个更主观的问题,因为所问的问题涉及if-this-then-then的几个步骤,这本身就很麻烦,因此会导致繁琐的表达。我赞成第一种,但不重视或教条。

时间复杂度是相同的。表现很可能非常重要。第二个内部乍一看似乎更多地将统计员联系起来,这可能使其稍微慢一些,但我不会在这方面下很多钱。如果我在这里非常关心表现,那么我肯定会分析两者。

+0

谢谢。就可读性而言,我只是通过添加回车符和缩进来对代码进行一些细微更改,使其更加真实。现在,你怎么看? – Neo

+1

它确实有助于分解每个步骤,但是在每个步骤中均匀分配,所以两者都得到了同样的改进,我仍然非常轻微地倾向于第一步,但只是稍微有点,并不期望每个人都会同意这一点。 –

+0

我刚刚分析了两种方法,并将结果作为更新粘贴到问题中。看起来第二种方法表现更好。但是我认为无论数据集的类型或大小如此微不足道,它都不值得在现实中考虑。但我可能是错的。 – Neo

相关问题