foldLeft وfoldRight
اختزل المجموعات إلى قيمة
foldLeft وfoldRight درس مجاني في Scala for Backend Engineering & Functional Programming على CoddyKit. هذا هو الدرس 3 من أصل 4. يمكنك قراءة الدرس كاملاً أدناه مجاناً — ثم تمرن عليه مباشرة في المتصفح باستخدام محرر أكواد مدمج ومدرس ذكاء اصطناعي متاح 24/7. هذا الدرس جزء من مسار التعلم في Scala for Backend Engineering & Functional Programming، وتقدمك يتزامن عبر الويب وتطبيق CoddyKit. تتضمن دورة Scala for Backend Engineering & Functional Programming 4 دروس في المجموع.
طيّ مجموعة
يختزل الطي مجموعة إلى قيمة واحدة عبر دمج العناصر مرارًا باستخدام مراكم.
إن نمط المراكم الذي تعلمته هو بالضبط ما يجرّده fold. فبدلًا من كتابة الدالة المساعدة ذات الاستدعاء الذاتي بنفسك، تمرر قيمة ابتدائية ودالة دمج.
أساسيات foldLeft
تأخذ foldLeft مراكمًا ابتدائيًا ودالة (acc, element)، ثم تتنقل في المجموعة من اليسار إلى اليمين.
في كل خطوة، تستبدل المراكم بنتيجة الدالة.
val xs = List(1, 2, 3, 4)
val total = xs.foldLeft(0)((acc, x) => acc + x)
@main def run(): Unit =
println(total) // 10كيفية تجميع foldLeft
يضع foldLeft الأقواس بدءًا من اليسار. بالنسبة إلى List(1, 2, 3) مع البذرة z، يحسب f(f(f(z, 1), 2), 3).
المراكم هو الوسيطة اليسرى، لذلك يتراكم أثناء تحركك نحو اليمين عبر القائمة.
// List(1, 2, 3).foldLeft(0)(_ + _)
// = ((0 + 1) + 2) + 3
// = 6أساسيات foldRight
يدمج foldRight العناصر أيضًا، لكنه يبدأ من اليمين.
تأخذ دالته (element, acc)، بحيث يكون العنصر على اليسار والمراكم على اليمين.
val xs = List(1, 2, 3, 4)
val total = xs.foldRight(0)((x, acc) => x + acc)
@main def run(): Unit =
println(total) // 10كيفية تجميع foldRight
يضع foldRight الأقواس بدءًا من اليمين. بالنسبة إلى List(1, 2, 3) مع البذرة z، يحسب f(1, f(2, f(3, z))).
توجد البذرة في أقصى اليمين، وتُدمج القائمة باتجاه الداخل بدءًا من نهايتها.
// List(1, 2, 3).foldRight(0)(_ + _)
// = 1 + (2 + (3 + 0))
// = 6متى يكون الاتجاه مهمًا
بالنسبة إلى العمليات التجميعية والتبادلية، مثل الجمع أو الضرب، يعطي الطيّان الإجابة نفسها.
أما في العمليات غير التبادلية، مثل الطرح أو بناء القوائم، فيغيّر الاتجاه النتيجة. اختره عن قصد.
val xs = List(1, 2, 3)
val l = xs.foldLeft(0)(_ - _) // ((0-1)-2)-3 = -6
val r = xs.foldRight(0)(_ - _) // 1-(2-(3-0)) = 2
@main def run(): Unit =
println((l, r)) // (-6, 2)بناء قائمة
يُعد foldRight الخيار الطبيعي لإعادة بناء قائمة بالترتيب، لأنه يعمل من الذيل نحو الداخل، وتحافظ الإضافة إلى المقدمة على مواضع العناصر.
يُحوّل هذا كل عنصر مع الحفاظ على الترتيب.
val xs = List(1, 2, 3)
val doubled = xs.foldRight(List.empty[Int]) { (x, acc) =>
(x * 2) :: acc
}
@main def run(): Unit =
println(doubled) // List(2, 4, 6)يعكس foldLeft الترتيب
إذا بنيت قائمة باستخدام foldLeft وأضفت العناصر إلى المقدمة، فستظهر النتيجة معكوسة، لأن العناصر تُضاف إلى المقدمة أثناء تحركك نحو اليمين.
قد يكون هذا بالضبط ما تريده أحيانًا.
val xs = List(1, 2, 3)
val rev = xs.foldLeft(List.empty[Int]) { (acc, x) =>
x :: acc
}
@main def run(): Unit =
println(rev) // List(3, 2, 1)أمان المكدس
يستخدم foldLeft الاستدعاء الذاتي النهائي ويعمل كحلقة، لذا فهو آمن مع المجموعات الضخمة.
أما foldRight على List فليس ذا استدعاء ذاتي نهائي، وقد يتسبب في تجاوز سعة المكدس مع القوائم الطويلة جدًا. فضّل foldLeft عندما لا تحتاج إلى الترتيب من اليمين إلى اليسار.
// Safe even for millions of elements:
val n = (1 to 1000000).foldLeft(0L)(_ + _)
// foldRight on a long List risks StackOverflowErrorتغيير نوع النتيجة
يمكن أن يختلف نوع المراكم عن نوع العناصر.
نطوي هنا قائمة من الأعداد الصحيحة إلى سلسلة نصية، لذلك تكون البذرة سلسلة فارغة، وتضيف كل خطوة عنصرًا.
يُحدَّد نوع fold انطلاقًا من البذرة.
val xs = List(1, 2, 3)
val s = xs.foldLeft("")((acc, x) => acc + x.toString)
@main def run(): Unit =
println(s) // "123"الطي كأداة متعددة الاستخدامات
تُعد عمليات كثيرة على القوائم حالات خاصة من fold، مثل sum وproduct وlength وmax وmap وfilter وreverse.
يساعدك إدراك وجود fold وراء هذه العمليات على كتابة تعليمات موجزة وتصريحية بدلًا من كتابة استدعاء ذاتي يدوي.
val xs = List(4, 1, 7, 3)
val maxV = xs.foldLeft(Int.MinValue)(_ max _)
val len = xs.foldLeft(0)((acc, _) => acc + 1)
@main def run(): Unit =
println((maxV, len)) // (7, 4)تحقق سريع
فكّر في اتجاه الطي وموضع البذرة.
مراجعة
يتنقل foldLeft من اليسار إلى اليمين، مع وجود المراكم على اليسار، ويحسب ((z op a) op b) op c. وهو ذو استدعاء ذاتي نهائي وآمن من ناحية المكدس.
يتنقل foldRight من اليمين إلى اليسار، مع وجود البذرة على اليمين، ويحسب a op (b op (c op z)). وهو مناسب لبناء القوائم مع الحفاظ على ترتيبها، لكنه قد يتسبب في تجاوز سعة المكدس مع القوائم الطويلة.
تحدد البذرة نوع النتيجة، لذلك يمكن للطي تحويل مجموعة إلى أي قيمة.
تعلم Scala مع معلم ذكاء اصطناعي — مجانًا
اكتب وقم بتشغيل أكوادك الفعلية في المتصفح، واحصل على مساعدة فورية من معلم ذكاء اصطناعي متاح 24/7، واستمر من حيث توقفت على الويب أو في التطبيق.
- الدورات
- 39
- الدروس
- 143
الأسئلة الشائعة
هل درس «foldLeft وfoldRight» مجاني؟
نعم — نص درس «foldLeft وfoldRight» كامل متاح مجاناً هنا على الويب. لتمرينه بشكل تفاعلي (محرر أكواد مدمج ومدرس ذكاء اصطناعي متاح 24/7) وفتح باقي دورة Scala for Backend Engineering & Functional Programming، انتقل إلى CoddyKit PRO. تتضمن دورة Scala for Backend Engineering & Functional Programming 4 دروس في المجموع.
ماذا ستتعلم في «foldLeft وfoldRight»؟
اختزل المجموعات إلى قيمة تتمرن على Scala for Backend Engineering & Functional Programming مع أكواد عملية تشغلها مباشرة في المتصفح، ومدرس ذكاء اصطناعي متاح 24/7 يجيب على أسئلتك أثناء عملك.
هل أحتاج إلى خبرة سابقة لأبدأ Scala for Backend Engineering & Functional Programming؟
لا تُشترط خبرة سابقة. Scala for Backend Engineering & Functional Programming على CoddyKit منظم للمبتدئين حتى المتقدمين، لذا يمكنك البدء من هنا أو من البداية والتقدم بسرعتك الخاصة. هذا هو الدرس 3 من أصل 4.
كم من الوقت يستغرق درس «foldLeft وfoldRight»؟
معظم دروس CoddyKit تستغرق حوالي 5–10 دقائق. كل منها موجز وتفاعلي، لذا تحرز تقدماً مستمراً وتستأنف من حيث توقفت عبر الويب والتطبيق.
هل يمكنني كتابة وتشغيل أكواد في درس Scala for Backend Engineering & Functional Programming هذا؟
نعم. كل درس في Scala for Backend Engineering & Functional Programming يتضمن محرر أكواد مدمج، لذا تكتب وتشغل أكواداً حقيقية مباشرة في متصفحك وتحصل على تعليقات فورية من الذكاء الاصطناعي — بدون إعداد محلي.
جميع الدروس في هذه الدورة
- التفكير递归يًا
- أنماط المُجمِّع
- foldLeft وfoldRight
- reduce وaggregate