Bu topallık gibi gelebilir, ama gerçekten iyi bir açıklama bulamadım Aggregate
.
İyi, küçük ve açık bir örnekle kısa, açıklayıcı, kapsamlı anlamına gelir.
Bu topallık gibi gelebilir, ama gerçekten iyi bir açıklama bulamadım Aggregate
.
İyi, küçük ve açık bir örnekle kısa, açıklayıcı, kapsamlı anlamına gelir.
Yanıtlar:
Anlaşılması en kolay tanımı Aggregate
, listenin her bir elemanı üzerinde, daha önce yapılmış olan işlemleri dikkate alarak bir işlem gerçekleştirmesidir. Yani, birinci ve ikinci eleman üzerindeki eylemi gerçekleştirir ve sonucu ileri taşır. Sonra önceki sonuç ve üçüncü eleman üzerinde çalışır ve ileriye doğru devam eder. vb.
Örnek 1. Sayıları toplama
var nums = new[]{1,2,3,4};
var sum = nums.Aggregate( (a,b) => a + b);
Console.WriteLine(sum); // output: 10 (1+2+3+4)
Bu ekler 1
ve 2
yapmak 3
. Sonra yapmak için 3
(önceki sonucun sonucu) ve 3
(sırayla bir sonraki eleman ) ekler 6
. Sonra ekler 6
ve 4
yapmak 10
.
Örnek 2. bir dizeden csv oluşturma
var chars = new []{"a","b","c", "d"};
var csv = chars.Aggregate( (a,b) => a + ',' + b);
Console.WriteLine(csv); // Output a,b,c,d
Bu aynı şekilde çalışır. Concatenate a
virgül ve b
yapmak a,b
. Sonra a,b
bir virgül ve c
yapmak için bitiştirir a,b,c
. ve bunun gibi.
Örnek 3. Bir tohum kullanarak sayıları çarpma
Bütünlüğü sağlamak için, bir olduğu aşırı bir Aggregate
tohum değeri alır.
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)
Yukarıdaki örneklere çok benzer şekilde, bu bir değeri ile başlar 5
ve 10
sonucu veren sekansın ilk elemanı ile çarpar 50
. Bu sonuç ileriye taşınır ve 20
bir sonuç vermek için dizideki bir sonraki sayıyla çarpılır 1000
. Bu, dizinin geri kalan 2 elemanı boyunca devam eder.
Canlı örnekler: http://rextester.com/ZXZ64749
Dokümanlar: http://msdn.microsoft.com/en-us/library/bb548651.aspx
ek
Yukarıdaki örnek 2, virgülle ayrılmış değerlerin bir listesini oluşturmak için dize birleştirmeyi kullanır. Bu, Aggregate
bu cevabın amacı olan kullanımı açıklamanın basit bir yoludur . Bununla birlikte, bu tekniği gerçekten büyük miktarda virgülle ayrılmış veri oluşturmak için kullanırsanız, a'nın kullanılması daha uygun olur StringBuilder
ve bu, Aggregate
başlatmak için tohumlanmış aşırı yükün kullanılmasıyla tamamen uyumludur 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);
Güncelleme örneği: http://rextester.com/YZCVXV6464
TakeWhile
bir zincir oluşturmayı öneririm Aggregate
- kolayca zincirlenebilirler. Yani sonunda TakeWhile(a => a == 'a').Aggregate(....)
. Bu örneğe bakın: rextester.com/WPRA60543
var csv = string.Join(",", chars)
(agrega veya dize oluşturucuya gerek yok) - ama evet, cevabın amacının agrega örnek kullanımı vermek olduğunu biliyorum, bu yüzden havalı. Ama yine de sadece dizelere katılmak için tavsiye edilmediğini belirtmek istedim, zaten bunun için adanmış bir yöntem var ....
var biggestAccount = Accounts.Aggregate((a1, a2) => a1.Amount >= a2.Amount ? a1 : a2);
Kısmen hangi aşırı yükten bahsettiğinize bağlıdır, ancak temel fikir şudur:
(currentValue, sequenceValue)
uygulama(nextValue)
currentValue = nextValue
currentValue
Yazıyı Edulinq serimde bulabilirsinizAggregate
yararlı - bir daha ayrıntılı (çeşitli aşırı dahil) açıklamasına ve uygulamaları içermektedir.
Basit bir örnek aşağıdakilere Aggregate
alternatif olarak kullanmaktır 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);
Veya belki de dizelerin tüm uzunluklarını bir dizi dizede toplamak:
int total = sequence.Aggregate(0, (current, item) => current + item.Length);
Şahsen nadirenAggregate
yararlı buluyorum - "özel" toplama yöntemleri genellikle benim için yeterince iyi.
Süper kısa Agrega Haskell / ML / F # 'da kat gibi çalışır.
Biraz daha uzun . .Aggregate (), geliştiricinin başlangıç durumunu (aka tohum olarak) ve toplama işlevini belirtmesine izin verdiği için genelleştirilmiş bir toplayıcıdır.
Kısa bir açıklama istediğini biliyorum ama başkalarının birkaç kısa cevap verdiğini düşündüm, belki biraz daha uzun biriyle ilgileneceğini düşündüm
Kodlu uzun versiyon Neyin ne olduğunu göstermenin bir yolu, bir kez foreach ve bir kez .Aggregate kullanarak örnek standart sapmayı nasıl uyguladığınızı gösterebilir. Not: Burada performansa öncelik vermedim, bu yüzden gereksiz yere koleksiyon üzerinde birkaç kez tekrar ediyorum
İlk olarak, ikinci dereceden mesafelerin toplamını oluşturmak için kullanılan bir yardımcı işlev:
static double SumOfQuadraticDistance (double average, int value, double state)
{
var diff = (value - average);
return state + diff * diff;
}
Sonra ForEach kullanarak Örnek Standart Sapma:
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));
}
Sonra bir kez kullanarak.
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));
}
Bu işlevlerin sumOfQuadraticDistance'ın nasıl hesaplandığı dışında özdeş olduğunu unutmayın:
var state = seed;
foreach (var value in ints)
{
state = SumOfQuadraticDistance (average, value, state);
}
var sumOfQuadraticDistance = state;
Karşı:
var sumOfQuadraticDistance = ints
.Aggregate (
seed,
(state, value) => SumOfQuadraticDistance (average, value, state)
);
Yani .Aggregate'in yaptığı, bu toplayıcı modelini kapsadığı ve .Aggregate'in uygulanmasının şöyle görüneceğini umuyorum:
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;
}
Standart sapma işlevlerini kullanmak şöyle görünecektir:
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);
Benim nacizane fikrime göre
.Aggregate okunabilirliğe yardımcı oluyor mu? Genel olarak LINQ'yu seviyorum çünkü düşünüyorum. Agrega bütünlük nedenlerinden ötürü Linq'te olmak zorundadır, ancak şahsen o kadar ikna olmadım.
SampleStandardDeviation_Aggregate()
ve SampleStandardDeviation_ForEach()
olamaz private
(varsayılan olarak bir erişim niteleyicisi yokluğunda), bu yüzden ya tahakkuk ettirilmiş olmalıydı public
veya internal
bana öyle görünüyor
Hatırlatma:
Func<X, Y, R>
iki tip girişX
veY
tip bir sonuç verir olduğunu,R
.
Agrega'da üç aşırı yükleme var:
Aşırı yük 1:
A Aggregate<A>(IEnumerable<A> a, Func<A, A, A> f)
Misal:
new[]{1,2,3,4}.Aggregate((x, y) => x + y); // 10
Bu aşırı yükleme basittir, ancak aşağıdaki sınırlamalara sahiptir:
InvalidOperationException
.Aşırı yük 2:
B Aggregate<A, B>(IEnumerable<A> a, B bIn, Func<B, A, B> f)
Misal:
var hayStack = new[] {"straw", "needle", "straw", "straw", "needle"};
var nNeedles = hayStack.Aggregate(0, (n, e) => e == "needle" ? n+1 : n); // 2
Bu aşırı yüklenme daha geneldir:
bIn
).Aşırı yük 3:
C Aggregate<A,B,C>(IEnumerable<A> a, B bIn, Func<B,A,B> f, Func<B,C> f2)
Üçüncü aşırı yük çok yararlı IMO değildir.
Aynı şey, aşırı yüklenme 2 ve ardından sonucunu dönüştüren bir fonksiyon kullanılarak daha kısa sürede yazılabilir.
Resimler bu mükemmel blog yazısından uyarlanmıştır .
Aggegate
.net içinde aşırı yük yoktur Func<T, T, T>
.
seed
, akümülatör fonksiyonunu N -1 kez uyguladığını gözlemliyoruz ; (diğer aşırı yükler iken do almak bir seed
) akümülatör fonksiyonunu uygulamak N kez.
Agrega temel olarak verileri Gruplamak veya Özetlemek için kullanılır.
MSDN'ye göre "Toplama İşlevi Bir dizi üzerine bir akümülatör işlevi uygular."
Örnek 1: Bir dizideki tüm sayıları ekleyin.
int[] numbers = new int[] { 1,2,3,4,5 };
int aggregatedValue = numbers.Aggregate((total, nextValue) => total + nextValue);
* important: Varsayılan olarak ilk toplam değer, toplama sırasındaki 1 öğedir. ie: toplam değişken başlangıç değeri varsayılan olarak 1 olacaktır.
değişken açıklama
total: işlev tarafından döndürülen toplam değeri (toplanmış değer) tutacaktır.
nextValue: dizi dizisindeki sonraki değerdir. Bu değer, toplam değere, yani toplam değerine eklenir.
Örnek 2: Bir dizideki tüm öğeleri ekleyin. Ayrıca 10 ile eklemeye başlamak için ilk akümülatör değerini ayarlayın.
int[] numbers = new int[] { 1,2,3,4,5 };
int aggregatedValue = numbers.Aggregate(10, (total, nextValue) => total + nextValue);
argüman açıklaması:
ilk argüman, dizideki bir sonraki değerle toplamaya başlamak için kullanılacak başlangıç değeridir (başlangıç değeri, yani tohum değeri).
ikinci argüman 2 int alan bir fonktur.
1. toplam: bu, hesaplamadan sonra işlev tarafından döndürülen toplama değerinden (toplanan değer) önceki ile aynı olacaktır.
2.nextValue:: dizi dizisindeki sonraki değerdir. Bu değer, toplam değere, yani toplam değerine eklenir.
Ayrıca bu kodda hata ayıklamak, toplamın nasıl çalıştığını daha iyi anlamanıza yardımcı olur.
Jamiec'den çok şey öğrendim .
Tek ihtiyaç CSV dizesi oluşturmaksa, bunu deneyebilirsiniz.
var csv3 = string.Join(",",chars);
İşte 1 milyon dizeyle bir test
0.28 seconds = Aggregate w/ String Builder
0.30 seconds = String.Join
Kaynak kodu burada
Buradaki tüm harika cevaplara ek olarak, bir dizi dönüşüm adımında bir öğeyi yürümek için de kullandım.
Bir dönüşüm a olarak uygulanırsa, a Func<T,T>
öğesine birkaç dönüşüm ekleyebilir List<Func<T,T>>
ve her adımda Aggregate
bir örneğini yürütmek için kullanabilirsiniz T
.
Bir string
değer almak ve bunu programlı olarak oluşturulabilecek bir dizi metin dönüşümünden geçmek istiyorsunuz .
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);
Bu bir dönüşüm zinciri oluşturacaktır: Baştaki ve sondaki boşlukları kaldırın -> ilk karakteri kaldır -> son karakteri kaldır -> büyük harfe dönüştür. Gerekli her türlü dönüşüm boru hattını oluşturmak için bu zincirdeki adımlar gerektiğinde eklenebilir, çıkarılabilir veya yeniden sıralanabilir.
Bu spesifik boru hattının nihai sonucu, " cat "
olur "A"
.
Bunun herhangi bir şeyT
olabileceğini anladıktan sonra bu çok güçlü olabilir . Bu, örnek olarak , filtreler gibi görüntü dönüşümleri için kullanılabilir ;BitMap
Tanım
Toplama yöntemi, genel koleksiyonlar için bir genişletme yöntemidir. Toplama yöntemi, koleksiyonun her öğesine bir işlev uygular. Sadece bir işlev uygulamakla kalmaz, sonucunu bir sonraki yineleme için başlangıç değeri olarak alır. Sonuç olarak, bir koleksiyondan hesaplanmış bir değer (min, maks, ort veya başka bir istatistiksel değer) alırız.
Bu nedenle, Toplam yöntemi, özyinelemeli bir işlevin güvenli bir şekilde uygulanmasıdır.
Güvenli , çünkü özyineleme bir koleksiyonun her öğesi üzerinde yinelenir ve yanlış çıkış koşulu ile sonsuz döngü süspansiyonu alamazız. Özyinelemeli , çünkü geçerli işlevin sonucu bir sonraki işlev çağrısı için parametre olarak kullanılır.
Sözdizimi:
collection.Aggregate(seed, func, resultSelector);
Nasıl çalışır:
var nums = new[]{1, 2};
var result = nums.Aggregate(1, (result, n) => result + n); //result = (1 + 1) + 2 = 4
var result2 = nums.Aggregate(0, (result, n) => result + n, response => (decimal)response/2.0); //result2 = ((0 + 1) + 2)*1.0/2.0 = 3*1.0/2.0 = 3.0/2.0 = 1.5
Pratik kullanım:
int n = 7;
var numbers = Enumerable.Range(1, n);
var factorial = numbers.Aggregate((result, x) => result * x);
Bu işlevle aynı şeyi yapıyor:
public static int Factorial(int n)
{
if (n < 1) return 1;
return n * Factorial(n - 1);
}
var numbers = new[]{3, 2, 6, 4, 9, 5, 7};
var avg = numbers.Aggregate(0.0, (result, x) => result + x, response => (double)response/(double)numbers.Count());
var min = numbers.Aggregate((result, x) => (result < x)? result: x);
var path = @“c:\path-to-folder”;
string[] txtFiles = Directory.GetFiles(path).Where(f => f.EndsWith(“.txt”)).ToArray<string>();
var output = txtFiles.Select(f => File.ReadAllText(f, Encoding.Default)).Aggregate<string>((result, content) => result + content);
File.WriteAllText(path + “summary.txt”, output, Encoding.Default);
Console.WriteLine(“Text files merged into: {0}”, output); //or other log info
Bu, Aggregate
Linq Sorting gibi bir Akıcı API üzerinde kullanımla ilgili bir açıklamadır .
var list = new List<Student>();
var sorted = list
.OrderBy(s => s.LastName)
.ThenBy(s => s.FirstName)
.ThenBy(s => s.Age)
.ThenBy(s => s.Grading)
.ThenBy(s => s.TotalCourses);
ve bir dizi alanı alan bir sıralama işlevi uygulamak istediğimizi görelim, Aggregate
for-loop yerine şu şekilde kullanımı çok kolaydır :
public static IOrderedEnumerable<Student> MySort(
this List<Student> list,
params Func<Student, object>[] fields)
{
var firstField = fields.First();
var otherFields = fields.Skip(1);
var init = list.OrderBy(firstField);
return otherFields.Skip(1).Aggregate(init, (resultList, current) => resultList.ThenBy(current));
}
Ve bunu şu şekilde kullanabiliriz:
var sorted = list.MySort(
s => s.LastName,
s => s.FirstName,
s => s.Age,
s => s.Grading,
s => s.TotalCourses);
Herkes açıklamasını yaptı. Benim açıklamam böyle.
Toplama yöntemi, koleksiyonun her öğesine bir işlev uygular. Örneğin, {6, 2, 8, 3} koleksiyonuna ve sahip olduğu Ekle (işleç +) işlevine sahip olalım (((6 + 2) +8) +3) ve 19 döndürür
var numbers = new List<int> { 6, 2, 8, 3 };
int sum = numbers.Aggregate(func: (result, item) => result + item);
// sum: (((6+2)+8)+3) = 19
Bu örnekte lambda ifadesi yerine Add adlı yöntem kullanılmıştır.
var numbers = new List<int> { 6, 2, 8, 3 };
int sum = numbers.Aggregate(func: Add);
// sum: (((6+2)+8)+3) = 19
private static int Add(int x, int y) { return x + y; }
Kısa ve temel bir tanım şu olabilir: Linq Agrega genişletme yöntemi, bir işlenenin iki olduğu bir listenin öğelerine uygulanan bir tür özyinelemeli işlev bildirmeye izin verir: Listede bulundukları sırayla öğeler, bir kerede bir öğe ve önceki özyinelemeli yinelemenin sonucu veya henüz özyineleme değilse hiçbir şey.
Bu şekilde sayıların faktöriyelini hesaplayabilir veya dizeleri birleştirebilirsiniz.
Çok boyutlu bir tamsayı dizisindeki sütunları toplamak için kullanılan toplama
int[][] nonMagicSquare =
{
new int[] { 3, 1, 7, 8 },
new int[] { 2, 4, 16, 5 },
new int[] { 11, 6, 12, 15 },
new int[] { 9, 13, 10, 14 }
};
IEnumerable<int> rowSums = nonMagicSquare
.Select(row => row.Sum());
IEnumerable<int> colSums = nonMagicSquare
.Aggregate(
(priorSums, currentRow) =>
priorSums.Select((priorSum, index) => priorSum + currentRow[index]).ToArray()
);
Dizini ile seç, Toplama işlevi içinde eşleşen sütunları toplamak ve yeni bir Dizi döndürmek için kullanılır; {3 + 2 = 5, 1 + 4 = 5, 7 + 16 = 23, 8 + 5 = 13}.
Console.WriteLine("rowSums: " + string.Join(", ", rowSums)); // rowSums: 19, 27, 44, 46
Console.WriteLine("colSums: " + string.Join(", ", colSums)); // colSums: 25, 24, 45, 42
Ancak, bir Boolean dizisindeki trues sayısını saymak daha zordur çünkü biriken tip (int) kaynak tipinden (bool) farklıdır; burada ikinci aşırı yükü kullanmak için bir tohum gereklidir.
bool[][] booleanTable =
{
new bool[] { true, true, true, false },
new bool[] { false, false, false, true },
new bool[] { true, false, false, true },
new bool[] { true, true, false, false }
};
IEnumerable<int> rowCounts = booleanTable
.Select(row => row.Select(value => value ? 1 : 0).Sum());
IEnumerable<int> seed = new int[booleanTable.First().Length];
IEnumerable<int> colCounts = booleanTable
.Aggregate(seed,
(priorSums, currentRow) =>
priorSums.Select((priorSum, index) => priorSum + (currentRow[index] ? 1 : 0)).ToArray()
);
Console.WriteLine("rowCounts: " + string.Join(", ", rowCounts)); // rowCounts: 3, 1, 2, 2
Console.WriteLine("colCounts: " + string.Join(", ", colCounts)); // colCounts: 3, 2, 1, 2
[1,2,3,4]
olacak . Ancak tek bir değerin bir dizisini döndürmek yerine, değerin kendisini alırsınız.[3,3,4]
[6,4]
[10]