0Pricing
Scala for Backend Engineering & Functional Programming · درس

reduce وaggregate

طرائق أخرى لدمج العناصر

reduce وaggregate درس مجاني في Scala for Backend Engineering & Functional Programming على CoddyKit. هذا هو الدرس 4 من أصل 4. يمكنك قراءة الدرس كاملاً أدناه مجاناً — ثم تمرن عليه مباشرة في المتصفح باستخدام محرر أكواد مدمج ومدرس ذكاء اصطناعي متاح 24/7. هذا الدرس جزء من مسار التعلم في Scala for Backend Engineering & Functional Programming، وتقدمك يتزامن عبر الويب وتطبيق CoddyKit. تتضمن دورة Scala for Backend Engineering & Functional Programming 4 دروس في المجموع.

من fold إلى reduce

قد ترغب أحيانًا في دمج العناصر من دون توفير قيمة بذرة منفصلة.

يستخدم reduce العنصر الأول بوصفه المراكم الابتدائي، ثم يدمج بقية العناصر فيه.

إنه نظير أخف من fold للحالات التي يكون فيها نوع العناصر ونوع النتيجة متماثلين.

أساسيات reduce

تأخذ reduce دالة ثنائية (a, b) وتطبقها على المجموعة، من دون قيمة ابتدائية صريحة.

بالنسبة إلى الجمع، فهي تضيف كل العناصر إلى بعضها ببساطة.

val xs = List(1, 2, 3, 4)
val total = xs.reduce((a, b) => a + b)

@main def run(): Unit =
  println(total)  // 10

مشكلة المجموعة الفارغة

لأن reduce لا يستخدم بذرة، فإن استدعاءه على مجموعة فارغة يطرح UnsupportedOperationException.

يكون كل من fold وfoldLeft آمنًا مع المجموعات الفارغة، لأنهما يعودان إلى البذرة المقدمة.

استخدم reduce فقط عندما تعرف أن المجموعة غير فارغة.

// List.empty[Int].reduce(_ + _)
// throws UnsupportedOperationException

List.empty[Int].foldLeft(0)(_ + _)  // safe, returns 0

استخدام reduceOption للأمان

تعيد reduceOption قيمة من النوع Option، وتعيد None للمجموعة الفارغة بدلًا من طرح استثناء.

هذه هي الطريقة الآمنة لاستخدام reduce عندما يكون احتمال الفراغ واردًا.

val xs = List(5, 9, 2)
val maybeMax = xs.reduceOption(_ max _)

@main def run(): Unit =
  println(maybeMax)  // Some(9)

reduceLeft وreduceRight

مثل fold، يوفّر reduce نسخًا تعتمد على الاتجاه.

تجمع reduceLeft العناصر من اليسار إلى اليمين، بينما تجمع reduceRight العناصر من اليمين إلى اليسار. أما reduce العادي فلا يضمن ترتيبًا معينًا للمجموعات المتوازية، لذا استخدم النسخة الصريحة عندما يكون الاتجاه مهمًا.

val xs = List(1, 2, 3)
val l = xs.reduceLeft(_ - _)   // (1-2)-3 = -4
val r = xs.reduceRight(_ - _)  // 1-(2-3) = 2

@main def run(): Unit =
  println((l, r))  // (-4, 2)

لماذا يوجد aggregate

يتطلب كل من fold وreduce علاقة بسيطة بين نوع المجمّع ونوع العنصر.

أما aggregate فهو أكثر أشكال fold عمومية: إذ يتيح أن يكون نوع المجمّع مختلفًا، ويخبر Scala بكيفية دمج المجمّعات الجزئية، وهذا مهم في المعالجة المتوازية.

توقيع aggregate

يأخذ aggregate قيمة ابتدائية، وseqop لطيّ عنصر داخل المجمّع، وcombop لدمج مجمّعين.

نادراً ما يُستخدم combop مع مجموعة متسلسلة؛ أما مع المجموعة المتوازية فيجمع نتائج كل جزء.

val xs = List(1, 2, 3, 4)
val sum = xs.aggregate(0)(
  (acc, x) => acc + x,   // seqop
  (a, b)   => a + b      // combop
)

@main def run(): Unit = println(sum)  // 10

aggregate مع نوع مختلف

يستخدم aggregate هنا لطيّ قائمة من الكلمات إلى مجموع واحد من النوع Int يمثل أطوالها.

يضيف seqop طول كل كلمة، بينما يجمع combop مجموعين جزئيين معًا.

يختلف نوع المجمّع (Int) عن نوع العناصر (String).

val words = List("hi", "there", "you")
val chars = words.aggregate(0)(
  (acc, w) => acc + w.length,
  (a, b)   => a + b
)

@main def run(): Unit = println(chars)  // 10

التجميع المتوازي

تظهر القوة الحقيقية لـ aggregate مع المجموعات المتوازية.

يطوي كل خيط جزءه باستخدام seqop، ثم تُدمج الأجزاء باستخدام combop. تتيح الدالتان لـ Scala تقسيم العمل وإعادة جمعه بأمان.

// Conceptual: par splits the work
// val n = data.par.aggregate(0)(_ + _.length, _ + _)
// seqop runs per chunk, combop merges chunk results

اختيار الأداة المناسبة

استخدم reduce أو reduceOption عندما يساوي نوع النتيجة نوع العناصر، ويكون الدمج تجميعيًا.

استخدم foldLeft عندما تحتاج إلى قيمة ابتدائية أو إلى نوع نتيجة مختلف في المعالجة المتسلسلة.

استخدم aggregate عندما يختلف نوعا المجمّع والعنصر، وتريد دمجًا مناسبًا للمعالجة المتوازية.

// reduce:    same type, non-empty, associative
// foldLeft:  seed + different type, sequential
// aggregate: different type + parallel merge

الدمج في مرور واحد

يمكن لـ aggregate حساب عدة أمور في الوقت نفسه عبر التجميع داخل tuple.

نحصل هنا على المجموع والعدد معًا في مرور واحد، مع دمج tuples داخل combop.

val xs = List(2, 4, 6, 8)
val (s, c) = xs.aggregate((0, 0))(
  (acc, x) => (acc._1 + x, acc._2 + 1),
  (a, b)   => (a._1 + b._1, a._2 + b._2)
)

@main def run(): Unit = println((s, c))  // (20, 4)

اختبار سريع

حدّد العملية الأكثر أمانًا لقائمة قد تكون فارغة.

مراجعة

يدمج reduce العناصر من دون قيمة ابتدائية، مستخدمًا العنصر الأول كنقطة بداية؛ ويطرح استثناءً عند التعامل مع مجموعة فارغة، بينما يعيد reduceOption القيمة None بدلًا من ذلك.

aggregate هو أكثر أشكال fold عمومية: قيمة ابتدائية، وseqop لطيّ العناصر، وcombop لدمج المجمّعات الجزئية في العمل المتوازي.

اختر reduce للدمج التجميعي من النوع نفسه، وfoldLeft للطيّ المتسلسل ذي القيمة الابتدائية، وaggregate عندما تختلف الأنواع أو تستخدم المعالجة المتوازية.

الأسئلة الشائعة

هل درس «reduce وaggregate» مجاني؟

نعم — نص درس «reduce وaggregate» كامل متاح مجاناً هنا على الويب. لتمرينه بشكل تفاعلي (محرر أكواد مدمج ومدرس ذكاء اصطناعي متاح 24/7) وفتح باقي دورة Scala for Backend Engineering & Functional Programming، انتقل إلى CoddyKit PRO. تتضمن دورة Scala for Backend Engineering & Functional Programming 4 دروس في المجموع.

ماذا ستتعلم في «reduce وaggregate»؟

طرائق أخرى لدمج العناصر تتمرن على Scala for Backend Engineering & Functional Programming مع أكواد عملية تشغلها مباشرة في المتصفح، ومدرس ذكاء اصطناعي متاح 24/7 يجيب على أسئلتك أثناء عملك.

هل أحتاج إلى خبرة سابقة لأبدأ Scala for Backend Engineering & Functional Programming؟

لا تُشترط خبرة سابقة. Scala for Backend Engineering & Functional Programming على CoddyKit منظم للمبتدئين حتى المتقدمين، لذا يمكنك البدء من هنا أو من البداية والتقدم بسرعتك الخاصة. هذا هو الدرس 4 من أصل 4.

كم من الوقت يستغرق درس «reduce وaggregate»؟

معظم دروس CoddyKit تستغرق حوالي 5–10 دقائق. كل منها موجز وتفاعلي، لذا تحرز تقدماً مستمراً وتستأنف من حيث توقفت عبر الويب والتطبيق.

هل يمكنني كتابة وتشغيل أكواد في درس Scala for Backend Engineering & Functional Programming هذا؟

نعم. كل درس في Scala for Backend Engineering & Functional Programming يتضمن محرر أكواد مدمج، لذا تكتب وتشغل أكواداً حقيقية مباشرة في متصفحك وتحصل على تعليقات فورية من الذكاء الاصطناعي — بدون إعداد محلي.

جميع الدروس في هذه الدورة

  1. التفكير递归يًا
  2. أنماط المُجمِّع
  3. foldLeft وfoldRight
  4. reduce وaggregate
← العودة إلى Scala for Backend Engineering & Functional Programming