Giải thích thuật toán tổng hợp LINQ


722

Điều này nghe có vẻ khập khiễng, nhưng tôi đã không thể tìm thấy một lời giải thích thực sự tốt về Aggregate .

Tốt có nghĩa là ngắn gọn, mô tả, toàn diện với một ví dụ nhỏ và rõ ràng.

Câu trả lời:


1015

Định nghĩa dễ hiểu nhất Aggregatelà nó thực hiện một thao tác trên từng thành phần của danh sách có tính đến các hoạt động đã đi trước đó. Đó là để nói rằng nó thực hiện hành động trên phần tử thứ nhất và thứ hai và mang kết quả về phía trước. Sau đó, nó hoạt động trên kết quả trước đó và yếu tố thứ ba và tiến về phía trước. Vân vân.

Ví dụ 1. Tổng hợp số

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

Điều này thêm 12để thực hiện 3. Sau đó thêm 3(kết quả của trước đó) và 3(yếu tố tiếp theo trong chuỗi) để thực hiện 6. Sau đó thêm 64thực hiện 10.

Ví dụ 2. tạo một csv từ một chuỗi các chuỗi

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

Điều này hoạt động theo nhiều cách tương tự. Nối amột dấu phẩy và bthực hiện a,b. Sau đó nối a,b với dấu phẩy và cthực hiện a,b,c. và như thế.

Ví dụ 3. Nhân số bằng cách sử dụng hạt giống

Để hoàn thiện, có một sự quá tải trong Aggregateđó có một giá trị hạt giống.

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)

Giống như các ví dụ trên, điều này bắt đầu bằng một giá trị 5và nhân nó với phần tử đầu tiên của chuỗi 10cho kết quả 50. Kết quả này được chuyển tiếp và nhân với số tiếp theo trong chuỗi 20để đưa ra kết quả 1000. Điều này tiếp tục thông qua 2 yếu tố còn lại của chuỗi.

Ví dụ trực tiếp: http://rextester.com/ZXZ64749
Tài liệu: http://msdn.microsoft.com/en-us/l Library / bb548651.aspx


Phụ lục

Ví dụ 2, ở trên, sử dụng nối chuỗi để tạo danh sách các giá trị được phân tách bằng dấu phẩy. Đây là một cách đơn giản để giải thích việc sử dụng Aggregateđó là ý định của câu trả lời này. Tuy nhiên, nếu sử dụng kỹ thuật này để thực sự tạo ra một lượng lớn dữ liệu được phân tách bằng dấu phẩy, thì sẽ phù hợp hơn khi sử dụng StringBuildervà điều này hoàn toàn tương thích với Aggregateviệc sử dụng quá tải hạt giống để bắt đầu 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);

Ví dụ cập nhật: http://rextester.com/YZCVXV6464


11
Một lời giải thích khác cho mô tả đầu tiên là hàm bạn cung cấp luôn kết hợp hai thành viên đầu tiên cho đến khi mảng được thu nhỏ thành một phần tử. Vì vậy, [1,2,3,4]sẽ là [3,3,4]sau đó [6,4]và cuối cùng [10]. Nhưng thay vì trả về một mảng của một giá trị, bạn chỉ cần lấy chính giá trị đó.
David Raab

2
Tôi có thể ngắt / thoát sớm khỏi chức năng Tổng hợp không? Ví dụ: chars.Aggregate ((a, b) => {if (a == 'a') phá vỡ toàn bộ tổng hợp khác trả về a + ',' + b})
Jeff Tian

13
@JeffTian - Tôi sẽ đề nghị xâu chuỗi TakeWhilesau đó Aggregate- đó là nhịp đập của các tiện ích mở rộng - chúng có thể dễ dàng xâu chuỗi . Vì vậy, bạn kết thúc với TakeWhile(a => a == 'a').Aggregate(....). Xem ví dụ này: rextester.com/WPRA60543
Jamiec

2
Là một phụ bản của phần phụ lục, toàn bộ khối có thể dễ dàng được thay thế bằng var csv = string.Join(",", chars)(không cần tổng hợp hoặc trình tạo chuỗi) - nhưng vâng, tôi biết điểm của câu trả lời là đưa ra cách sử dụng tổng hợp sao cho thật tuyệt. Nhưng tôi vẫn muốn đề cập đến việc không nên tham gia chuỗi, đã có một phương pháp dành riêng cho điều đó ....
T_D

2
một cách sử dụng phổ biến khác (cho đến nay tôi chỉ thấy trong mã sản xuất) là lấy các mục tối thiểu hoặc tối đa nhưvar biggestAccount = Accounts.Aggregate((a1, a2) => a1.Amount >= a2.Amount ? a1 : a2);
Franck

133

Nó một phần phụ thuộc vào mức độ quá tải mà bạn đang nói đến, nhưng ý tưởng cơ bản là:

  • Bắt đầu với một hạt giống là "giá trị hiện tại"
  • Lặp lại theo trình tự. Đối với mỗi giá trị trong chuỗi:
    • Áp dụng hàm do người dùng chỉ định để chuyển đổi (currentValue, sequenceValue)thành(nextValue)
    • Bộ currentValue = nextValue
  • Trả lại trận chung kết currentValue

Bạn có thể thấy Aggregatebài đăng trong loạt Edulinq của tôi hữu ích - nó bao gồm một mô tả chi tiết hơn (bao gồm các tình trạng quá tải khác nhau) và việc triển khai.

Một ví dụ đơn giản là sử dụng Aggregatethay thế cho 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);

Hoặc có lẽ tổng hợp tất cả độ dài của chuỗi trong chuỗi chuỗi:

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

Cá nhân tôi hiếm khi thấy Aggregatehữu ích - các phương pháp tổng hợp "phù hợp" thường đủ tốt cho tôi.


6
@Jon Có các biến thể không đồng bộ của Uẩn chia các mục thành một cây để công việc có thể được phân chia giữa các lõi không? Có vẻ như thiết kế của phương pháp này phù hợp với các khái niệm "giảm" hoặc "gấp", nhưng tôi không biết liệu nó có thực sự làm điều đó dưới mui xe hay chỉ đơn giản là lặp qua danh sách các mục.
AaronLS

@Jon: edulink được đề cập ở trên không hoạt động, bạn có thể chuyển hướng tôi đến đúng liên kết. Và bạn có thể vui lòng cụ thể hơn về thuật ngữ các hàm tổng hợp "được tùy chỉnh" mà bạn đã sử dụng trong câu trả lời của mình không.
Koushik

1
@Koushik: Tôi đã sửa liên kết trong bài viết. Theo các hàm tổng hợp "được tùy chỉnh", ý tôi là những thứ như Max / Min / Count / Sum.
Jon Skeet

62

Tổng hợp siêu ngắn hoạt động như nếp gấp trong Haskell / ML / F #.

Hơi dài hơn một chút .Max (), .Min (), .Sum (), .Alusive () tất cả lặp lại trên các phần tử trong một chuỗi và tổng hợp chúng bằng cách sử dụng hàm tổng hợp tương ứng. .Aggregate () là tổng hợp tổng quát ở chỗ nó cho phép nhà phát triển chỉ định trạng thái bắt đầu (còn gọi là seed) và hàm tổng hợp.

Tôi biết bạn đã yêu cầu một lời giải thích ngắn nhưng tôi đoán rằng những người khác đã đưa ra một vài câu trả lời ngắn gọn. Tôi nghĩ rằng bạn có thể sẽ quan tâm đến một câu hỏi dài hơn

Phiên bản dài với mã Một cách để minh họa những gì nó có thể được hiển thị cách bạn triển khai Độ lệch chuẩn mẫu một lần bằng cách sử dụng foreach và một lần sử dụng .Aggregate. Lưu ý: Tôi không ưu tiên hiệu suất ở đây vì vậy tôi lặp đi lặp lại nhiều lần so với colleciton một cách không cần thiết

Đầu tiên một hàm trợ giúp được sử dụng để tạo tổng khoảng cách bậc hai:

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

Sau đó, Độ lệch chuẩn mẫu sử dụng 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));
}

Sau đó, một lần sử dụng .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));
}

Lưu ý rằng các hàm này giống hệt nhau ngoại trừ cách tính sumOfQuadraticDistance:

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

Đấu với:

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

Vì vậy, những gì .Aggregate làm là nó gói gọn mẫu tổng hợp này và tôi hy vọng rằng việc triển khai .Aggregate sẽ trông giống như thế này:

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;
}

Sử dụng các hàm độ lệch chuẩn sẽ trông giống như thế này:

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);

IMHO

Vì vậy, .Aggregate giúp dễ đọc? Nói chung, tôi yêu LINQ bởi vì tôi nghĩ Tổng hợp phải ở Linq vì lý do đầy đủ nhưng cá nhân tôi không tin lắm .Aggregate thêm khả năng đọc so với một bài thuyết minh được viết tốt.


+1 Tuyệt vời! Nhưng các phương thức mở rộng SampleStandardDeviation_Aggregate()SampleStandardDeviation_ForEach()không thể private(theo mặc định là không có vòng loại truy cập), do đó, nên đã được tích lũy bởi một trong hai publichoặc internal, dường như đối với tôi
Fulproof

FYI: Nếu tôi nhớ chính xác các phương thức mở rộng trong mẫu của tôi là một phần của cùng một lớp đã sử dụng chúng ==> công việc riêng tư trong trường hợp này.
Chỉ là một siêu dữ liệu khác

39

một bưc tranh đang gia ngan lơi noi

Nhắc nhở:
Func<X, Y, R>là một hàm có hai đầu vào loại XY, trả về kết quả của loại R.

Có thể đếm được. Đăng ký có ba lần quá tải:


Quá tải 1:

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

Tổng hợp1

Thí dụ:

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


Quá tải này là đơn giản, nhưng nó có những hạn chế sau:

  • chuỗi phải chứa ít nhất một phần tử,
    nếu không hàm sẽ ném một InvalidOperationException.
  • các yếu tố và kết quả phải cùng loại.



Quá tải 2:

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

Tổng hợp2

Thí dụ:

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


Quá tải này là tổng quát hơn:

  • một giá trị hạt giống phải được cung cấp ( bIn).
  • bộ sưu tập có thể trống
    trong trường hợp này, hàm sẽ mang lại giá trị hạt giống như kết quả.
  • các yếu tố và kết quả có thể có các loại khác nhau.



Quá tải 3:

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


Quá tải thứ ba không phải là IMO rất hữu ích.
Điều tương tự có thể được viết ngắn gọn hơn bằng cách sử dụng quá tải 2 theo sau là một hàm biến đổi kết quả của nó.


Các minh họa được điều chỉnh từ blogpost tuyệt vời này .


Đây sẽ là một câu trả lời tuyệt vời .... về một câu hỏi về Haskel. Nhưng không có quá tải Aggegatetrong .net mà phải mất một Func<T, T, T>.
Jamiec

4
Có đấy . Bạn sử dụng nó trong câu trả lời của riêng bạn!
3dGrabber

1
Nâng cao vì bạn mô tả cẩn thận những gì xảy ra khi chuỗi trống. Gọi N là số phần tử trong nguồn. Chúng tôi quan sát rằng quá tải không mất a seed, áp dụng hàm tích lũy N -1 lần; trong khi các quá tải khác ( thực hiện a seed) áp dụng hàm tích lũy N lần.
Jeppe Stig Nielsen

17

Tổng hợp về cơ bản được sử dụng để Nhóm hoặc Tổng hợp dữ liệu.

Theo MSDN "Hàm tổng hợp Áp dụng hàm tích lũy trên một chuỗi."

Ví dụ 1: Thêm tất cả các số trong một mảng.

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

* quan trọng: Giá trị tổng hợp ban đầu theo mặc định là phần tử 1 trong chuỗi bộ sưu tập. tức là: tổng giá trị ban đầu của biến sẽ là 1 theo mặc định.

giải thích biến

tổng: nó sẽ giữ giá trị tổng (giá trị tổng hợp) được trả về bởi func.

nextValue: nó là giá trị tiếp theo trong chuỗi mảng. Giá trị này được thêm vào giá trị tổng hợp tức là tổng.

Ví dụ 2: Thêm tất cả các mục trong một mảng. Đồng thời đặt giá trị tích lũy ban đầu để bắt đầu thêm từ 10.

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

lập luận giải thích:

đối số đầu tiên là giá trị ban đầu (giá trị khởi đầu tức là giá trị seed) sẽ được sử dụng để bắt đầu bổ sung với giá trị tiếp theo trong mảng.

đối số thứ hai là một func là một func có 2 int.

1.total: giá trị này sẽ giữ nguyên như trước giá trị tổng (giá trị tổng hợp) được trả về bởi func sau khi tính toán.

2.nextValue :: nó là giá trị tiếp theo trong chuỗi mảng. Giá trị này được thêm vào giá trị tổng hợp tức là tổng.

Ngoài ra gỡ lỗi mã này sẽ cho bạn hiểu rõ hơn về cách tổng hợp làm việc.


7

Đã học được rất nhiều từ câu trả lời của Jamiec .

Nếu nhu cầu duy nhất là tạo chuỗi CSV, bạn có thể thử điều này.

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

Đây là một thử nghiệm với 1 triệu chuỗi

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

Mã nguồn ở đây


Khi tôi chạy cùng một mã trong dotnetfiddle.net như được cung cấp trong liên kết, tôi đã nhận được "Lỗi nghiêm trọng: Giới hạn sử dụng bộ nhớ đã bị vượt quá" đối với "chuỗi.Join" nhưng Aggregate luôn hoạt động như mong đợi. Vì vậy, tôi tin rằng điều này không được khuyến khích sử dụng String.Join
Manish Jain

Lạ nhỉ? Khi tôi nhận xét Đồng hồ bấm giờ đầu tiên dành cho Tổng hợp; sau đó tôi không nhận được bất kỳ "Lỗi nghiêm trọng: Đã vượt quá giới hạn sử dụng bộ nhớ". Vui lòng giải thích! Liên kết: dotnetfiddle.net/6YyumS
Manish Jain

dotnetfiddle.net có giới hạn bộ nhớ, khi đạt đến điểm dừng thực thi. nếu bạn di chuyển mã tổng hợp trước mã String.Join, bạn có thể gặp lỗi cho tổng hợp.
Rm558

7

Ngoài tất cả các câu trả lời tuyệt vời ở đây, tôi cũng đã sử dụng nó để dẫn một mục qua một loạt các bước chuyển đổi.

Nếu một phép biến đổi được triển khai như một Func<T,T>, bạn có thể thêm một vài phép biến đổi vào a List<Func<T,T>>và sử dụng Aggregateđể đi qua một thể hiện của Ttừng bước.

Một ví dụ cụ thể hơn

Bạn muốn nhận một stringgiá trị và đưa nó qua một loạt các biến đổi văn bản có thể được xây dựng theo chương trình.

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);

Điều này sẽ tạo ra một chuỗi các phép biến đổi: Xóa các khoảng trắng ở đầu và cuối -> xóa ký tự đầu tiên -> xóa ký tự cuối cùng -> chuyển đổi sang chữ hoa. Các bước trong chuỗi này có thể được thêm, xóa hoặc sắp xếp lại khi cần thiết, để tạo ra bất kỳ loại đường ống chuyển đổi nào được yêu cầu.

Kết quả cuối cùng của đường ống cụ thể này, là " cat "trở thành "A".


Điều này có thể trở nên rất mạnh mẽ một khi bạn nhận ra rằng Tcó thể là bất cứ điều gì . Điều này có thể được sử dụng để biến đổi hình ảnh, như bộ lọc, sử dụng BitMaplàm ví dụ;


4

Định nghĩa

Phương pháp tổng hợp là một phương pháp mở rộng cho các bộ sưu tập chung. Phương pháp tổng hợp áp dụng một chức năng cho từng mục của bộ sưu tập. Không chỉ áp dụng một hàm, mà lấy kết quả của nó làm giá trị ban đầu cho lần lặp tiếp theo. Do đó, kết quả là chúng ta sẽ nhận được một giá trị được tính toán (min, max, avg hoặc giá trị thống kê khác) từ một bộ sưu tập.

Do đó, phương pháp Tổng hợp là một hình thức thực hiện an toàn của hàm đệ quy.

An toàn , vì đệ quy sẽ lặp lại qua từng mục của bộ sưu tập và chúng tôi không thể có bất kỳ đình chỉ vòng lặp vô hạn nào do điều kiện thoát sai. Đệ quy , vì kết quả của hàm hiện tại được sử dụng làm tham số cho lệnh gọi hàm tiếp theo.

Cú pháp:

collection.Aggregate(seed, func, resultSelector);
  • hạt giống - giá trị ban đầu theo mặc định;
  • func - chức năng đệ quy của chúng tôi. Nó có thể là biểu thức lambda, đại biểu Func hoặc kiểu hàm TF (kết quả T, T nextValue);
  • resultSelector - nó có thể là một hàm như func hoặc một biểu thức để tính toán, biến đổi, thay đổi, chuyển đổi kết quả cuối cùng.

Làm thế nào nó hoạt động:

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

Cách sử dụng thực tế:

  1. Tìm yếu tố từ một số n:

int n = 7;
var numbers = Enumerable.Range(1, n);
var factorial = numbers.Aggregate((result, x) => result * x);

đang làm điều tương tự như chức năng này:

public static int Factorial(int n)
{
   if (n < 1) return 1;

   return n * Factorial(n - 1);
}
  1. Tổng hợp () là một trong những phương thức mở rộng LINQ mạnh nhất, như Chọn () và Trong đó (). Chúng ta có thể sử dụng nó để thay thế Sum (), Min (). Chức năng Max (), Average () hoặc để thay đổi nó bằng cách triển khai bối cảnh bổ sung:
    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);
  1. Cách sử dụng phức tạp hơn của các phương thức mở rộng:
    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

Câu trả lời đầu tiên khá tốt. Làm tốt! Thật xấu hổ vì đó là một câu hỏi cũ hoặc bạn sẽ có rất nhiều câu hỏi
Jamiec

1

Đây là một lời giải thích về việc sử dụng AggregateAPI thông thạo như Linq Sắp xếp.

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);

và hãy xem chúng tôi muốn triển khai một hàm sắp xếp lấy một tập các trường, điều này rất dễ sử dụng Aggregatethay vì vòng lặp for, như thế này:

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));
}

Và chúng ta có thể sử dụng nó như thế này:

var sorted = list.MySort(
    s => s.LastName,
    s => s.FirstName,
    s => s.Age,
    s => s.Grading,
    s => s.TotalCourses);

1

Mọi người đã đưa ra lời giải thích của mình. Lời giải thích của tôi là như thế.

Phương pháp tổng hợp áp dụng một chức năng cho từng mục của bộ sưu tập. Ví dụ: hãy có bộ sưu tập {6, 2, 8, 3} và hàm Add (toán tử +) nó thực hiện (((6 + 2) +8) +3) và trả về 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

Trong ví dụ này có phương thức được đặt tên Thêm thay vì biểu thức 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; }

0

Một định nghĩa ngắn và thiết yếu có thể là thế này: Phương thức mở rộng Linq Aggregate cho phép khai báo một loại hàm đệ quy được áp dụng trên các phần tử của danh sách, các toán hạng có hai: các phần tử theo thứ tự chúng có trong danh sách, một yếu tố tại một thời điểm và kết quả của lần lặp đệ quy trước đó hoặc không có gì nếu chưa đệ quy.

Theo cách này, bạn có thể tính giai thừa của các số hoặc nối chuỗi.


0

Tổng hợp được sử dụng để tính tổng các cột trong một mảng số nguyên đa chiều

        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()
                );

Chọn với chỉ mục được sử dụng trong hàm tổng hợp để tổng các cột khớp và trả về một mảng mới; {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

Nhưng việc đếm số lượng dấu vết trong một mảng Boolean khó khăn hơn vì loại tích lũy (int) khác với loại nguồn (bool); ở đây một hạt giống là cần thiết để sử dụng quá tải thứ hai.

        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
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.