2016-11-30 11 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 호출을 사용합니다. 그러나 이것은 매우 큰 데이터 집합에서만 증명할 수 있었고 실제로 찍은 시간은 매우 작았습니다. 실제로 성능의 차이가 요소가 읽혀지는 횟수로 인해 각 요소가 (예 : 데이터베이스에 대한) 쿼리를 호출하면 더 작은 데이터 세트에서 더 중요 할 수 있습니다. 하지만 그 차이가 읽기 요소 사이의 오버 헤드로 인한 것이고 요소가 두 방법 중 동일한 횟수로 읽혀 진다면 성능 차이는 데이터 집합 크기 또는 요소 읽기 시간과 상관없이 항상 무시할 수있을 것입니다. (비주얼 스튜디오 성능 프로파일 러에서) 아래

결과 : 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 

는 그래서 그래, 그들은 동일한 의미를 갖는다. 특히 어떤 경우 든 비어있는 목록은 메서드에서 true을 의미하며 공백에서 오는 true이 호출을 All()으로 전달하거나 공백을 최종 All()으로 전달했는지 여부를 나타냅니다.

가독성은보다 주관적인 문제입니다. 질문하는 바로는 본질적으로 성가신 성가신 표현으로 이어질 수있는 몇 가지 단계가 포함되어 있기 때문입니다. 나는 첫 번째를 선호하지만 무겁게 또는 독단적으로하지 않는다.

시간 복잡도는 동일합니다. 성능은 많은 부분이 될 가능성이 있습니다. 두 번째의 내부 구조는 언뜻보기에 열거자를 좀 더 느리게 만들 수 있지만 더 많은 돈을 걸지는 않을 것입니다. 여기 성능에 대해 크게 신경을 쓰면 분명히 양쪽 모두를 프로파일 할 것입니다.

+0

감사합니다. 가독성 측면에서 필자는 캐리지 리턴과 들여 쓰기를 추가하여 좀 더 현실감있게 코드를 약간 변경했습니다. 자, 어떻게 생각하니? – Neo

+1

그것은 확실히 각각의 단계를 무너 뜨리는 데 도움이되지만 각각에 균등하게 적용되므로 둘 다 똑같이 향상됩니다. 나는 처음에는 여전히 약간 선호하지만 모두가 동의한다는 것을 기대하지는 않습니다. –

+0

방금 ​​두 가지 방법으로 프로파일을 작성했으며 질문을 업데이트로 붙여 넣었습니다. 두 번째 방법이 더 잘 수행되는 것 같습니다. 그러나 데이터 세트 유형이나 크기에 관계없이 무시할 만하다고 생각합니다. 현실에서는 고려할 가치가 없습니다. 그러나 나는 틀릴 수 있습니다. – Neo