2009-07-26 6 views
5

나는 초기 목록에서 해당 위치까지 각각의 결과에 int로 다른 IEnumerable<int>,에 IEnumerable<int> 변환하는 LINQ 쿼리와 함께 와서 모든 int 치의 합계입니다 노력하고 있어요 :Linq 쿼리에서 일련의 int 합계를 계산하는 방법은 무엇입니까?

을 감안할 때 int[] a
나는 int[] b
어디 b[0] = a[0], b[1] = a[0] + a[1], b[2] = a[0] + a[1] + a[2] 및 필요하므로

또는 합계 위 b[1] = b[0] + a[1], b[2] = b[1] + a[2]과 같이 쓸 수있다 등등,하지만 난 그 도움이 될 표시되지 않습니다에.

나는 물론, for 루프이 작업을 수행 할 수 있습니다,하지만 난 쿼리에서 A [] 순서를 얻어 나는 내가 그 쿼리를 계속하면 더 좋은 보는 대신 것이라고 생각 갑자기이 :)

for 추가

답변

13

글쎄, 당신은 꽤 구역질 비록, 충분히 쉽게 부작용와 함께 할 ...

int sum = 0; 
int[] b = a.Select(x => (sum += x)).ToArray(); 

틀이를 캡슐화하는 "실행 집계"의 종류를 제공하는 경우는, 좋은 것 수 있지만, 그것은 내가 아는 한 멀리 있지 않습니다.

+0

당신은 절대적으로 환상적 : 네, 다소 구역질이다, 그러나 충분히 좋은, 그리고 내가 최근에 문의를 제거하는 퀘스트입니다. –

8

얼마 전에 이것을 수행하는 함수를 작성했습니다. Haskell의 scanl 함수와 비슷합니다.

public static IEnumerable<TResult> Scan<T, TResult>(
    this IEnumerable<T> source, 
    Func<T, T, TResult> combine) 
{ 
    using (IEnumerator<T> data = source.GetEnumerator()) 
     if (data.MoveNext()) 
     { 
      T first = data.Current; 

      yield return first; 

      while (data.MoveNext()) 
      { 
       first = combine(first, data.Current); 
       yield return first; 
      } 
     } 
} 

int[] b = a 
    .Scan((running, current) => running + current) 
    .ToArray(); 
+1

'yield returns first'에 문제가 있습니다. TResult가 아닌 T 유형의 경우 * –

5

씨 스키트의 솔루션에 대한 대안 : 우리는 LINQ 쿼리에 대한 요구 사항을 삭제하고 더 말 그대로 해결하는 경우 "다른 IEnumerable<int>IEnumerable<int> 변환은"우리는이를 사용할 수 있습니다

static IEnumerable<int> Sum(IEnumerable<int> a) 
    { 
     int sum = 0; 
     foreach (int i in a) 
     { 
      sum += i; 
      yield return sum; 
     } 
    } 

하는 우리 무한 시리즈에 적용 할 수 있습니다.

foreach (int i in Sum(MyMath.NaturalNumbers)) 
     Console.WriteLine(i); 

이것은 전체 배열을 한 번에 만들지 않으려는 경우에도 유용합니다.

+0

예, 요구 사항을 설명하기가 쉽기 때문에 배열 구문을 사용했지만 인수는 실제로 IEnumerable 입니다. 그러나 Mr. Skeet은 여전히 ​​.ToArray() 호출없이 작동하며 더 작아서 아직 그 중 하나에 투표하고 있습니다. –

+0

물론 나는 "Mr. Skeet의 솔루션"을 의미했습니다 : P –

0

위의 대답은 작동하지 않습니다 .... 하스켈의 scanl과 동일한 서명을 공유하지 않습니다 .... 기본적으로 linq의 "집계"아이디어에 대한 확장 ...이 부분은 하스켈 구현

public static IEnumerable<TResult> Scanl<T, TResult>(
     this IEnumerable<T> source, 
     TResult first, 
     Func<TResult, T, TResult> combine) 
    { 
     using (IEnumerator<T> data = source.GetEnumerator()) 
     { 
      yield return first; 

      while (data.MoveNext()) 
      { 
       first = combine(first, data.Current); 
       yield return first; 
      } 
     } 
    } 

더 나은 사용

[TestMethod] 
    public void Scanl_Test() 
    { 
     var xs = new int[] { 1, 2, 3, 4, 5, 6, 7 }; 

     var lazyYs = xs.Scanl(0, (y, x) => y + x); 

     var ys = lazyYs.ToArray(); 

     Assert.AreEqual(ys[0], 0); 
     Assert.AreEqual(ys[1], 1); 
     Assert.AreEqual(ys[2], 3); 
     Assert.AreEqual(ys[3], 6); 
     Assert.AreEqual(ys[4], 10); 
     Assert.AreEqual(ys[5], 15); 
     Assert.AreEqual(ys[6], 21); 
     Assert.AreEqual(ys[7], 28); 
    } 
관련 문제