Ini mungkin terdengar lemah, tetapi saya belum dapat menemukan penjelasan yang sangat bagus Aggregate
.
Baik berarti pendek, deskriptif, komprehensif dengan contoh kecil dan jelas.
Ini mungkin terdengar lemah, tetapi saya belum dapat menemukan penjelasan yang sangat bagus Aggregate
.
Baik berarti pendek, deskriptif, komprehensif dengan contoh kecil dan jelas.
Jawaban:
Definisi yang paling mudah dipahami Aggregate
adalah melakukan operasi pada setiap elemen daftar dengan mempertimbangkan operasi yang telah berjalan sebelumnya. Maksudnya melakukan aksi pada elemen pertama dan kedua dan membawa hasilnya ke depan. Kemudian beroperasi pada hasil sebelumnya dan elemen ketiga dan berjalan maju. dll.
Contoh 1. Menjumlahkan angka
var nums = new[]{1,2,3,4};
var sum = nums.Aggregate( (a,b) => a + b);
Console.WriteLine(sum); // output: 10 (1+2+3+4)
Ini menambah 1
dan 2
membuat 3
. Kemudian tambahkan 3
(hasil sebelumnya) dan 3
(elemen berikutnya secara berurutan) untuk dibuat 6
. Kemudian tambahkan 6
dan 4
buat 10
.
Contoh 2. buat csv dari array string
var chars = new []{"a","b","c", "d"};
var csv = chars.Aggregate( (a,b) => a + ',' + b);
Console.WriteLine(csv); // Output a,b,c,d
Ini bekerja dengan cara yang hampir sama. Menggabungkan a
koma dan b
untuk membuat a,b
. Kemudian digabungkan a,b
dengan koma dan c
untuk membuatnya a,b,c
. dan seterusnya.
Contoh 3. Mengalikan angka menggunakan seed
Untuk kelengkapan, ada kelebihan dari Aggregate
yang membutuhkan nilai benih.
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)
Sama seperti contoh di atas, ini dimulai dengan nilai 5
dan mengalikannya dengan elemen pertama dari urutan 10
memberikan hasil 50
. Hasil ini diteruskan dan dikalikan dengan angka berikutnya dalam urutan 20
untuk memberikan hasil 1000
. Ini berlanjut melalui sisa 2 elemen dari urutan.
Contoh langsung: http://rextester.com/ZXZ64749
Documents: http://msdn.microsoft.com/en-us/library/bb548651.aspx
Tambahan
Contoh 2, di atas, menggunakan penggabungan string untuk membuat daftar nilai yang dipisahkan oleh koma. Ini adalah cara sederhana untuk menjelaskan penggunaan Aggregate
yang merupakan maksud dari jawaban ini. Namun, jika menggunakan teknik ini untuk benar-benar membuat sejumlah besar data yang dipisahkan koma, akan lebih tepat untuk menggunakan StringBuilder
, dan ini sepenuhnya kompatibel dengan Aggregate
menggunakan seeded overload untuk memulai 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);
Contoh yang diperbarui: http://rextester.com/YZCVXV6464
TakeWhile
sebuah Aggregate
- thats beatuty dari ekstensi Enumerable - mudah dirantai. Jadi Anda berakhir dengan TakeWhile(a => a == 'a').Aggregate(....)
. Lihat contoh ini: rextester.com/WPRA60543
var csv = string.Join(",", chars)
(tidak perlu agregat atau pembuat string) - tapi ya, saya tahu bahwa jawabannya adalah untuk memberikan contoh penggunaan agregat sehingga keren. Tapi saya masih ingin menyebutkan bahwa itu tidak disarankan untuk hanya bergabung dengan string, sudah ada metode yang didedikasikan untuk itu ....
var biggestAccount = Accounts.Aggregate((a1, a2) => a1.Amount >= a2.Amount ? a1 : a2);
Sebagian tergantung pada kelebihan beban yang Anda bicarakan, tetapi ide dasarnya adalah:
(currentValue, sequenceValue)
menjadi(nextValue)
currentValue = nextValue
currentValue
Anda mungkin menemukan Aggregate
posting dalam seri Edulinq saya bermanfaat - termasuk deskripsi yang lebih rinci (termasuk berbagai kelebihan) dan implementasi.
Salah satu contoh sederhana menggunakan Aggregate
sebagai alternatif untuk 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);
Atau mungkin menjumlahkan semua panjang string dalam urutan string:
int total = sequence.Aggregate(0, (current, item) => current + item.Length);
Secara pribadi saya jarang menemukan Aggregate
berguna - metode agregasi "disesuaikan" biasanya cukup baik untuk saya.
Agregat super pendek berfungsi seperti lipatan di Haskell / ML / F #.
Sedikit lebih lama .Max (), .Min (), .Sum (), .Rata-rata () semuanya mengulangi elemen-elemen secara berurutan dan menggabungkannya menggunakan fungsi agregat masing-masing. .Aggregate () adalah agregator yang digeneralisasi karena memungkinkan pengembang untuk menentukan status awal (alias seed) dan fungsi agregat.
Saya tahu Anda meminta penjelasan singkat tetapi saya pikir ketika orang lain memberikan beberapa jawaban singkat saya pikir Anda mungkin akan tertarik pada yang sedikit lebih lama
Versi panjang dengan kode Salah satu cara untuk menggambarkan apa fungsinya adalah menunjukkan bagaimana Anda menerapkan Contoh Standar Deviasi sekali menggunakan foreach dan sekali menggunakan .Aggregate. Catatan: Saya belum memprioritaskan kinerja di sini jadi saya harus mengulangi beberapa kali selama tidak perlu colleciton
Pertama, fungsi pembantu yang digunakan untuk membuat jumlah jarak kuadratik:
static double SumOfQuadraticDistance (double average, int value, double state)
{
var diff = (value - average);
return state + diff * diff;
}
Kemudian Contoh Deviasi Standar menggunakan 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));
}
Kemudian sekali menggunakan .Aregregate:
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));
}
Perhatikan bahwa fungsi-fungsi ini identik kecuali untuk bagaimana sumOfQuadraticDistance dihitung:
var state = seed;
foreach (var value in ints)
{
state = SumOfQuadraticDistance (average, value, state);
}
var sumOfQuadraticDistance = state;
Melawan:
var sumOfQuadraticDistance = ints
.Aggregate (
seed,
(state, value) => SumOfQuadraticDistance (average, value, state)
);
Jadi apa yang dilakukan .Aregregate adalah bahwa ia merangkum pola agregator ini dan saya berharap bahwa implementasi .Aggregate akan terlihat seperti ini:
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;
}
Menggunakan fungsi standar deviasi akan terlihat seperti ini:
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);
Menurut opini saya
Jadi, apakah .Aregregate membantu keterbacaan? Secara umum saya suka LINQ karena saya pikir. Dimana, .Pilih, .OrderBy dan seterusnya sangat membantu keterbacaan (jika Anda menghindari hirarki inline. Pilih). Agregat harus ada di Linq untuk alasan kelengkapan tetapi secara pribadi saya tidak begitu yakin bahwa. Agregat menambah keterbacaan dibandingkan dengan foreach yang ditulis dengan baik.
SampleStandardDeviation_Aggregate()
dan SampleStandardDeviation_ForEach()
tidak dapat private
(secara default tidak adanya kualifikasi akses), jadi seharusnya telah public
internal
Pengingat:
Func<X, Y, R>
adalah fungsi dengan dua input tipeX
danY
, yang mengembalikan hasil tipeR
.
Enumerable.Aggregate memiliki tiga kelebihan:
Kelebihan 1:
A Aggregate<A>(IEnumerable<A> a, Func<A, A, A> f)
Contoh:
new[]{1,2,3,4}.Aggregate((x, y) => x + y); // 10
Kelebihan ini sederhana, tetapi memiliki batasan berikut:
InvalidOperationException
.Kelebihan 2:
B Aggregate<A, B>(IEnumerable<A> a, B bIn, Func<B, A, B> f)
Contoh:
var hayStack = new[] {"straw", "needle", "straw", "straw", "needle"};
var nNeedles = hayStack.Aggregate(0, (n, e) => e == "needle" ? n+1 : n); // 2
Kelebihan ini lebih umum:
bIn
).Kelebihan 3:
C Aggregate<A,B,C>(IEnumerable<A> a, B bIn, Func<B,A,B> f, Func<B,C> f2)
Kelebihan ketiga adalah IMO yang tidak terlalu berguna.
Hal yang sama dapat ditulis lebih ringkas dengan menggunakan overload 2 diikuti oleh fungsi yang mengubah hasilnya.
Ilustrasi diadaptasi dari blogpost yang luar biasa ini .
Aggegate
dalam. Net yang membutuhkan Func<T, T, T>
.
seed
, berlaku fungsi akumulator N -1 kali; sedangkan overloads lain (yang tidak mengambil seed
) menerapkan fungsi akumulator N kali.
Agregat pada dasarnya digunakan untuk mengelompokkan atau menjumlahkan data.
Menurut MSDN "Fungsi Agregat Menerapkan fungsi akumulator pada suatu urutan."
Contoh 1: Tambahkan semua angka dalam array.
int[] numbers = new int[] { 1,2,3,4,5 };
int aggregatedValue = numbers.Aggregate((total, nextValue) => total + nextValue);
* Penting: Nilai agregat awal secara default adalah elemen 1 dalam urutan koleksi. yaitu: nilai total variabel awal akan menjadi 1 secara default.
penjelasan variabel
total: itu akan menyimpan nilai penjumlahan (nilai agregat) yang dikembalikan oleh func.
nextValue: ini adalah nilai berikutnya dalam urutan array. Nilai ini kemudian ditambahkan ke nilai agregat yaitu total.
Contoh 2: Tambahkan semua item dalam array. Juga atur nilai akumulator awal untuk mulai menambahkan dengan dari 10.
int[] numbers = new int[] { 1,2,3,4,5 };
int aggregatedValue = numbers.Aggregate(10, (total, nextValue) => total + nextValue);
penjelasan argumen:
argumen pertama adalah nilai awal (nilai awal yaitu nilai awal) yang akan digunakan untuk memulai penambahan dengan nilai berikutnya dalam array.
argumen kedua adalah fungsi yang merupakan fungsi yang membutuhkan 2 int.
1.total: ini akan tetap sama seperti sebelum nilai penjumlahan (nilai agregat) dikembalikan oleh func setelah perhitungan.
2.nextValue:: ini adalah nilai berikutnya dalam urutan array. Nilai ini kemudian ditambahkan ke nilai agregat yaitu total.
Juga debug kode ini akan memberi Anda pemahaman yang lebih baik tentang cara kerja agregat.
Belajar banyak dari jawaban Jamiec .
Jika satu-satunya kebutuhan adalah untuk menghasilkan string CSV, Anda dapat mencoba ini.
var csv3 = string.Join(",",chars);
Ini adalah tes dengan 1 juta string
0.28 seconds = Aggregate w/ String Builder
0.30 seconds = String.Join
Kode sumber ada di sini
Selain semua jawaban hebat di sini, saya juga menggunakannya untuk memandu item melalui serangkaian langkah transformasi.
Jika transformasi diimplementasikan sebagai a Func<T,T>
, Anda dapat menambahkan beberapa transformasi ke a List<Func<T,T>>
dan gunakan Aggregate
untuk menjalankan instance dari T
setiap langkah.
Anda ingin mengambil string
nilai, dan berjalan melalui serangkaian transformasi teks yang bisa dibangun secara programatik.
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);
Ini akan membuat rantai transformasi: Hapus spasi awal dan akhir -> hapus karakter pertama -> hapus karakter terakhir -> konversi ke huruf besar. Langkah-langkah dalam rantai ini dapat ditambahkan, dihapus, atau disusun ulang sesuai kebutuhan, untuk membuat jenis pipa transformasi apa pun yang diperlukan.
Hasil akhir dari pipa khusus ini, adalah " cat "
menjadi "A"
.
Ini bisa menjadi sangat kuat begitu Anda menyadari bahwa itu T
bisa menjadi apa saja . Ini dapat digunakan untuk transformasi gambar, seperti filter, menggunakan BitMap
sebagai contoh;
Definisi
Metode agregat adalah metode ekstensi untuk koleksi umum. Metode agregat berlaku fungsi untuk setiap item koleksi. Tidak hanya hanya menerapkan fungsi, tetapi mengambil hasilnya sebagai nilai awal untuk iterasi berikutnya. Jadi, sebagai hasilnya, kami akan mendapatkan nilai yang dihitung (min, maks, rata-rata, atau nilai statistik lainnya) dari koleksi.
Oleh karena itu, metode agregat adalah bentuk implementasi yang aman dari fungsi rekursif.
Aman , karena rekursi akan beralih ke setiap item koleksi dan kami tidak bisa mendapatkan suspensi loop tak terbatas dengan kondisi keluar yang salah. Rekursif , karena hasil fungsi saat ini digunakan sebagai parameter untuk panggilan fungsi berikutnya.
Sintaksis:
collection.Aggregate(seed, func, resultSelector);
Bagaimana itu bekerja:
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
Penggunaan praktis:
int n = 7;
var numbers = Enumerable.Range(1, n);
var factorial = numbers.Aggregate((result, x) => result * x);
yang melakukan hal yang sama dengan fungsi ini:
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
Ini adalah penjelasan tentang penggunaan Aggregate
pada API Lancar seperti Sortasi Linq.
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);
dan mari kita lihat kita ingin mengimplementasikan fungsi sortir yang mengambil seperangkat bidang, ini sangat mudah digunakan Aggregate
daripada for-loop, seperti ini:
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));
}
Dan kita bisa menggunakannya seperti ini:
var sorted = list.MySort(
s => s.LastName,
s => s.FirstName,
s => s.Age,
s => s.Grading,
s => s.TotalCourses);
Setiap orang telah memberikan penjelasannya. Penjelasan saya seperti itu.
Metode agregat berlaku fungsi untuk setiap item koleksi. Misalnya, mari kita koleksi {6, 2, 8, 3} dan fungsi Tambahkan (operator +) tidak (((6 + 2) +8) +3) dan mengembalikan 19
var numbers = new List<int> { 6, 2, 8, 3 };
int sum = numbers.Aggregate(func: (result, item) => result + item);
// sum: (((6+2)+8)+3) = 19
Dalam contoh ini ada yang lulus bernama metode Tambahkan bukan ekspresi lambda.
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; }
Definisi pendek dan esensial mungkin adalah ini: Metode ekstensi Agregat Linq memungkinkan untuk mendeklarasikan semacam fungsi rekursif yang diterapkan pada elemen daftar, operan di antaranya adalah dua: elemen dalam urutan di mana mereka hadir dalam daftar, satu elemen pada satu waktu, dan hasil dari iterasi rekursif sebelumnya atau tidak sama sekali jika belum rekursi.
Dengan cara ini Anda dapat menghitung faktorial angka, atau string gabungan.
Agregat digunakan untuk menjumlahkan kolom dalam array integer multi dimensi
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()
);
Pilih dengan indeks digunakan dalam fungsi Agregat untuk menjumlahkan kolom yang cocok dan mengembalikan Array baru; {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
Tetapi menghitung jumlah true dalam array Boolean lebih sulit karena tipe akumulasi (int) berbeda dari tipe sumber (bool); di sini benih diperlukan untuk menggunakan kelebihan kedua.
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]
juga[3,3,4]
saat itu[6,4]
dan akhirnya[10]
. Tetapi alih-alih mengembalikan array nilai tunggal Anda hanya mendapatkan nilai itu sendiri.