[c#] شرح LINQ Aggregate خوارزمية



Answers

يعتمد جزئياً على الحمل الزائد الذي تتحدث عنه ، لكن الفكرة الأساسية هي:

  • ابدأ بالبذور على أنها "القيمة الحالية"
  • تكرار عبر التسلسل. لكل قيمة في التسلسل:
    • تطبيق وظيفة محددة من قبل المستخدم لتحويل (currentValue, sequenceValue) إلى (nextValue)
    • Set currentValue = nextValue
  • ارجع إلى currentValue النهائية 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 مفيدة - طرق التجميع "المصممة" عادة ما تكون جيدة بما يكفي بالنسبة لي.

Question

قد يبدو هذا أعرجًا ، لكنني لم أتمكن من العثور على تفسير جيد Aggregate .

جيد يعني قصير وصفي وشامل مع مثال صغير وواضح.




تعلمت الكثير من جواب Jamiec's .

إذا كانت الحاجة الوحيدة هي إنشاء سلسلة CSV ، فيمكنك تجربة ذلك.

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

هنا اختبار مع 1 مليون السلاسل

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

كود المصدر هو here




صورة تساوي ألف كلمة

تذكير: Func<A, B, C> هي دالة ذات مدخلين من النوعين A و B ، وترجع C

Enumerable.Aggregate يحتوي على ثلاثة أحمال زائدة:


الزائد 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 متبوعًا بوظيفة تحول نتيجة ذلك.


تم تكييف الرسوم التوضيحية من هذا blogpost الممتاز .




قد يكون التعريف القصير والأساسي هو: Linq Aggregate extension method يسمح بالإعلان عن نوع من الدالة العودية المطبقة على عناصر القائمة ، المعاملين منهم هما: العناصر بالترتيب الذي توجد به في القائمة ، عنصر واحد في كل مرة ، ونتيجة للتكرار التكراري السابق أو لا شيء إن لم يكن بعد recursion.

وبهذه الطريقة ، يمكنك حساب عامل الأرقام من الأرقام ، أو تسلسل السلاسل.




تجميع يستخدم لجمع الأعمدة في صفيف صحيح متعدد الأبعاد

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

يتم استخدام Select with index داخل Acregate func لملء الأعمدة المتطابقة وإرجاع صفيف جديد؛ {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

لكن حساب عدد التراتب في مجموعة منطقية أكثر صعوبة لأن النوع المتراكم (int) يختلف عن نوع المصدر (bool) ؛ هنا البذور ضروري من أجل استخدام الزائد الثاني.

        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



Links



Tags

c# c#   .net .net   linq