LINQ Aggregate 알고리즘 설명 못했습니다 Aggregate. 좋은 것은 작고 명확한

이것은 절름발이 들릴지 모르지만에 대한 좋은 설명을 찾지 못했습니다 Aggregate.

좋은 것은 작고 명확한 예와 함께 짧고 설명 적이며 포괄적이라는 것을 의미합니다.



답변

가장 이해하기 쉬운 정의 Aggregate는 이전에 수행 한 작업을 고려하여 목록의 각 요소에 대해 작업을 수행한다는 것입니다. 즉, 첫 번째 요소와 두 번째 요소에 대해 작업을 수행하고 결과를 전달합니다. 그런 다음 이전 결과와 세 번째 요소에서 작동하여 계속 진행됩니다. 기타

예 1. 숫자 합산

var nums = new[]{1,2,3,4};
var sum = nums.Aggregate( (a,b) => a + b);
Console.WriteLine(sum); // output: 10 (1+2+3+4)

이 추가 1하고 2만들 수 3있습니다. 그런 다음 3(이전 결과) 및 3(다음 요소 순서대로)를 추가하여 만듭니다 6. 그런 다음 6and 4을 추가합니다 10.

예제 2. 문자열 배열에서 csv 만들기

var chars = new []{"a","b","c", "d"};
var csv = chars.Aggregate( (a,b) => a + ',' + b);
Console.WriteLine(csv); // Output a,b,c,d

이것은 거의 같은 방식으로 작동합니다. a쉼표를 연결 하고 b만드십시오 a,b. 그런 다음 a,b 쉼표로 연결하고을 c만듭니다 a,b,c. 등등.

예 3. 시드를 사용하여 숫자 곱하기

완전성 들어있다 과부하Aggregate시드 값을 취한다.

var multipliers = new []{10,20,30,40};
var multiplied = multipliers.Aggregate(5, (a,b) => a * b);
Console.WriteLine(multiplied); //Output 1200000 ((((5*10)*20)*30)*40)

위의 예 5와 마찬가지로이 값은 값으로 시작 하여 시퀀스의 첫 번째 요소에 곱하여 10결과를 제공합니다 50. 이 결과는 다음의 숫자로 이월되어 승산되어 20결과를 제공합니다 1000. 이것은 시퀀스의 나머지 2 요소를 통해 계속됩니다.

실제 예 : http://rextester.com/ZXZ64749
문서 : http://msdn.microsoft.com/en-us/library/bb548651.aspx


추가

위의 예 2에서는 문자열 연결을 사용하여 쉼표로 구분 된 값 목록을 만듭니다. 이것은 Aggregate이 답변의 의도 인 사용법을 설명하는 간단한 방법 입니다. 그러나이 기술을 사용하여 실제로 쉼표로 구분 된 대량의 데이터를 작성하는 경우을 사용하는 것이 더 적합 하며 시드 과부하를 사용하여을 시작하는 것과 StringBuilder완전히 호환됩니다 .AggregateStringBuilder

var chars = new []{"a","b","c", "d"};
var csv = chars.Aggregate(new StringBuilder(), (a,b) => {
    if(a.Length>0)
        a.Append(",");
    a.Append(b);
    return a;
});
Console.WriteLine(csv);

업데이트 된 예 : http://rextester.com/YZCVXV6464


답변

어떤 오버로드에 대해 부분적으로 의존하지만 기본 아이디어는 다음과 같습니다.

  • “현재 값”으로 시드로 시작
  • 시퀀스를 반복합니다. 시퀀스의 각 값에 대해 :
    • 변환 할 수있는 사용자 지정 기능 적용 (currentValue, sequenceValue)으로를(nextValue)
    • 세트 currentValue = nextValue
  • 최종 반환 currentValue

Aggregate내 Edulinq 시리즈게시물이 유용하다는 것을 알 수 있습니다. 자세한 내용 (다양한 과부하 포함)과 구현이 포함되어 있습니다.

하나의 간단한 예는 다음에 Aggregate대한 대안으로 사용 하는 것입니다 Count.

// 0 is the seed, and for each item, we effectively increment the current value.
// In this case we can ignore "item" itself.
int count = sequence.Aggregate(0, (current, item) => current + 1);

또는 일련의 문자열에서 모든 문자열 길이를 합산하십시오.

int total = sequence.Aggregate(0, (current, item) => current + item.Length);

개인적으로 나는 거의 찾을 수없는 Aggregate유용한 -은 “맞춤형”집계 방법은 나를 위해 일반적으로 충분하다.


답변

Super short
Aggregate는 Haskell / ML / F #에서 접기처럼 작동합니다.

약간 더 긴
.Max (), .Min (), .Sum (), .Average ()는 모든 요소를 ​​순서대로 반복하고 각 집계 함수를 사용하여 집계합니다. .Aggregate ()는 개발자가 시작 상태 (일명 시드)와 집계 함수를 지정할 수 있다는 점에서 일반화 된 집계 자입니다.

나는 당신이 짧은 설명을 요구했다는 것을 알고 있지만 다른 사람들이 짧은 대답을 몇 개 주었을 때 약간 더 긴 것에 관심이 있다고 생각했습니다.

코드가있는 긴 버전 foreach를 사용하고 .Aggregate를 사용하여 한 번 샘플 표준 편차
를 구현하는 방법을 보여줄 수있는 한 가지 방법이 있습니다 . 참고 : 나는 여기서 성능 우선 순위를 정하지 않았으므로 불필요하게 colleciton을 여러 번 반복합니다.

먼저 이차 거리의 합을 만드는 데 사용되는 도우미 함수 :

static double SumOfQuadraticDistance (double average, int value, double state)
{
    var diff = (value - average);
    return state + diff * diff;
}

그런 다음 ForEach를 사용하여 표준 편차를 샘플링하십시오.

static double SampleStandardDeviation_ForEach (
    this IEnumerable<int> ints)
{
    var length = ints.Count ();
    if (length < 2)
    {
        return 0.0;
    }

    const double seed = 0.0;
    var average = ints.Average ();

    var state = seed;
    foreach (var value in ints)
    {
        state = SumOfQuadraticDistance (average, value, state);
    }
    var sumOfQuadraticDistance = state;

    return Math.Sqrt (sumOfQuadraticDistance / (length - 1));
}

그런 다음 .Aggregate를 사용하여 한 번 :

static double SampleStandardDeviation_Aggregate (
    this IEnumerable<int> ints)
{
    var length = ints.Count ();
    if (length < 2)
    {
        return 0.0;
    }

    const double seed = 0.0;
    var average = ints.Average ();

    var sumOfQuadraticDistance = ints
        .Aggregate (
            seed,
            (state, value) => SumOfQuadraticDistance (average, value, state)
            );

    return Math.Sqrt (sumOfQuadraticDistance / (length - 1));
}

sumOfQuadraticDistance가 계산되는 방식을 제외하고 이러한 함수는 동일합니다.

var state = seed;
foreach (var value in ints)
{
    state = SumOfQuadraticDistance (average, value, state);
}
var sumOfQuadraticDistance = state;

대:

var sumOfQuadraticDistance = ints
    .Aggregate (
        seed,
        (state, value) => SumOfQuadraticDistance (average, value, state)
        );

따라서 .Aggregate 가하는 것은이 집계 자 패턴을 캡슐화하고 .Aggregate의 구현이 다음과 같이 보일 것으로 기대합니다.

public static TAggregate Aggregate<TAggregate, TValue> (
    this IEnumerable<TValue> values,
    TAggregate seed,
    Func<TAggregate, TValue, TAggregate> aggregator
    )
{
    var state = seed;

    foreach (var value in values)
    {
        state = aggregator (state, value);
    }

    return state;
}

표준 편차 함수를 사용하면 다음과 같습니다.

var ints = new[] {3, 1, 4, 1, 5, 9, 2, 6, 5, 4};
var average = ints.Average ();
var sampleStandardDeviation = ints.SampleStandardDeviation_Aggregate ();
var sampleStandardDeviation2 = ints.SampleStandardDeviation_ForEach ();

Console.WriteLine (average);
Console.WriteLine (sampleStandardDeviation);
Console.WriteLine (sampleStandardDeviation2);

이모

그렇다면 .Aggregate는 가독성에 도움이됩니까? 일반적으로 나는 .LINQ를 좋아합니다. 완전성 때문에 집계가 Linq에 있어야하지만 개인적으로 그렇게 확신하지는 않습니다. 집계는 잘 작성된 foreach에 비해 가독성을 추가합니다.


답변

그림은 천 단어의 가치가 있습니다

알림 :
Func<X, Y, R>유형 X및의 입력이 두 개인 함수이며 유형 Y의 결과를 반환합니다 R.

집계 가능 : 집계에는 세 가지 과부하가 있습니다.

과부하 1 :

A Aggregate<A>(IEnumerable<A> a, Func<A, A, A> f)

예:

new[]{1,2,3,4}.Aggregate((x, y) => x + y);  // 10

이 과부하는 간단하지만 다음과 같은 제한이 있습니다.

  • 시퀀스에는 적어도 하나의 요소가 포함되어야합니다.
    그렇지 않으면 함수가를 발생 InvalidOperationException시킵니다.
  • 요소와 결과는 동일한 유형이어야합니다.


과부하 2 :

B Aggregate<A, B>(IEnumerable<A> a, B bIn, Func<B, A, B> f)

예:

var hayStack = new[] {"straw", "needle", "straw", "straw", "needle"};
var nNeedles = hayStack.Aggregate(0, (n, e) => e == "needle" ? n+1 : n);  // 2

이 과부하가 더 일반적입니다.

  • 시드 값을 제공해야합니다 ( bIn).
  • 컬렉션이 비어있을 수 있습니다
    .이 경우 함수는 결과적으로 시드 값을 생성합니다.
  • 요소와 결과는 다른 유형을 가질 수 있습니다.


과부하 3 :

C Aggregate<A,B,C>(IEnumerable<A> a, B bIn, Func<B,A,B> f, Func<B,C> f2)

세 번째 과부하는 그다지 유용한 IMO가 아닙니다.
오버로드 2를 사용하고 결과를 변환하는 함수를 사용하여 더 간결하게 작성할 수 있습니다.

그림은 이 훌륭한 블로그 포스트 에서 수정되었습니다 .


답변

집계는 기본적으로 데이터를 그룹화하거나 요약하는 데 사용됩니다.

MSDN에 따르면 “집계 함수 시퀀스에 누산기 기능을 적용합니다.”

예 1 : 배열의 모든 숫자를 추가하십시오.

int[] numbers = new int[] { 1,2,3,4,5 };
int aggregatedValue = numbers.Aggregate((total, nextValue) => total + nextValue);

* 중요 : 기본적으로 초기 집계 값은 콜렉션 순서에서 1 요소입니다. 즉, 총 변수 초기 값은 기본적으로 1입니다.

변수 설명

total : func이 반환 한 합계 값 (집계 값)을 보유합니다.

nextValue : 배열 순서에서 다음 값입니다. 이 값은 집계 된 값, 즉 총계에 더해지는 것보다 큽니다.

예 2 : 배열의 모든 항목을 추가하십시오. 또한 10부터 시작하여 초기 누산기 값을 설정하십시오.

int[] numbers = new int[] { 1,2,3,4,5 };
int aggregatedValue = numbers.Aggregate(10, (total, nextValue) => total + nextValue);

인수 설명 :

첫 번째 인수는 배열의 다음 값으로 더하기 시작하는 데 사용되는 초기 값 (시작 값, 즉 시드 값)입니다.

두 번째 인수는 2 int를 취하는 func 인 func입니다.

1. 총계 : 계산 후 func에 의해 반환 된 합계 값 (집계 값) 이전과 동일합니다.

2.nextValue : : 배열 순서에서 다음 값입니다. 이 값은 집계 된 값, 즉 총계에 더해지는 것보다 큽니다.

또한이 코드를 디버깅하면 집계가 어떻게 작동하는지 더 잘 이해할 수 있습니다.


답변

Jamiec의 답변 에서 많은 것을 배웠습니다 .

CSV 문자열을 생성하는 것만 필요한 경우 시도해 볼 수 있습니다.

var csv3 = string.Join(",",chars);

백만 개의 문자열을 사용한 테스트입니다.

0.28 seconds = Aggregate w/ String Builder 
0.30 seconds = String.Join 

소스 코드는 여기


답변

이미 여기에있는 모든 훌륭한 답변 외에도 일련의 변형 단계를 통해 항목을 안내하는 데 사용했습니다.

변환이로 구현 된 경우 Func<T,T>여러 변환을에 추가 하고 각 단계 의 인스턴스를 진행 하는 데 List<Func<T,T>>사용할 수 있습니다 .AggregateT

보다 구체적인 예

당신은 먹고 싶어 string값을, 그리고 프로그래밍 방식으로 구축 할 수있는 텍스트 변환하는 일련의를 통해 도보.

var transformationPipeLine = new List<Func<string, string>>();
transformationPipeLine.Add((input) => input.Trim());
transformationPipeLine.Add((input) => input.Substring(1));
transformationPipeLine.Add((input) => input.Substring(0, input.Length - 1));
transformationPipeLine.Add((input) => input.ToUpper());

var text = "    cat   ";
var output = transformationPipeLine.Aggregate(text, (input, transform)=> transform(input));
Console.WriteLine(output);

이렇게하면 일련의 변형이 생성됩니다. 선행 및 후행 공백 제거-> 첫 문자 제거-> 마지막 문자 제거-> 대문자로 변환 이 체인의 단계는 필요에 따라 추가, 제거 또는 재정렬되어 필요한 모든 종류의 변환 파이프 라인을 생성 할 수 있습니다.

이 특정 파이프 라인의 최종 결과는, 즉 " cat "이된다 "A".


당신 T무엇이든 할 수 있다는 것을 깨닫게되면 이것은 매우 강력해질 수 있습니다 . BitMap예를 들어 필터와 같은 이미지 변환에 사용할 수 있습니다 .