이것은 절름발이 들릴지 모르지만에 대한 좋은 설명을 찾지 못했습니다 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
. 그런 다음 6
and 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
완전히 호환됩니다 .Aggregate
StringBuilder
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>>
사용할 수 있습니다 .Aggregate
T
보다 구체적인 예
당신은 먹고 싶어 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
예를 들어 필터와 같은 이미지 변환에 사용할 수 있습니다 .