فهارس في forEach Kotlin: كيف لا تفقد الموضع وتسريع الكود

مدرب بايثون أونلاين للمبتدئين

تعلم Python بسهولة دون إرهاق نظري. حل مهام عملية مع التحقق التلقائي واكتب الكود مباشرة في المتصفح.

ابدأ الدورة

كيفية الحصول على الفهرس الحالي في forEach Kotlin: من المبتدئ إلى المحترف

\n\n

تخيل: أنت تكتب بلغة Kotlin، وتعالج قائمة من المستخدمين، وفجأة تدرك أنك لا تحتاج فقط إلى العنصر، بل إلى موضعه في المجموعة. تلقائياً تمد يدك إلى الحلقة القديمة for (i in 0 until list.size)… توقف! في Kotlin هناك طرق أكثر أناقة وأداءً. في هذه المقالة، سنشرح كيفية الحصول على الفهرس الحالي في forEach Kotlin، ونقارن أداء الطرق المختلفة، ونختار الأفضل لمشروعك. هذه ليست مجرد ترجمة للوثائق - إنها نتيجة قياسات حقيقية وخبرة مجتمع Stack Overflow.

\n\n

لماذا يعتبر forEach بدون فهرس مشكلة؟

\n\n

الحلقة القياسية list.forEach { item -> ... } مريحة، ولكن عندما تحتاج إلى معرفة موضع العنصر، يكتب الكثيرون حلولاً مؤقتة:

\n\n
var index = 0\nlist.forEach { item ->\n    println("$index: $item")\n    index++\n}
\n\n

هذا يعمل، لكنه يبدو ضخماً وعرضة للأخطاء (نسيت الزيادة؟ حصلت على خطأ). علاوة على ذلك، المتغير القابل للتغيير خارج الحلقة هو انتهاك للأسلوب الوظيفي ومشكلة محتملة في السيناريوهات متعددة الخيوط. دعنا نلقي نظرة على الحلول الصحيحة.

\n\n

الطريقة 1: استخدام withIndex() - بسيط وأنيق

\n\n

الإجابة الأكثر شيوعاً على Stack Overflow هي الدالة withIndex(). إنها تُرجع سلسلة من أزواج IndexedValue، حيث يحتوي كل عنصر على حقل index وحقل value.

\n\n
val list = listOf("Kotlin", "Java", "Python")\nlist.withIndex().forEach { (index, value) ->\n    println("العنصر #$index: $value")\n}
\n\n

ماذا يحدث هنا؟ withIndex() تنشئ سلسلة كسولة (lazy)، تغلف كل عنصر في كائن IndexedValue. التفكيك (index, value) يجعل الكود نظيفاً وقابلاً للقراءة.

\n\n

المزايا:

\n
    \n
  • الإيجاز - سطر واحد بدلاً من ثلاثة
  • \n
  • الكسل - لا ينشئ مجموعات إضافية في الذاكرة
  • \n
  • قابلية القراءة - يظهر فوراً أننا نعمل مع فهرس
  • \n
\n\n

العيوب:

\n
    \n
  • زيادة طفيفة في التحميل بسبب إنشاء غلاف IndexedValue (لكن في 99% من الحالات يكون هذا غير ملحوظ)
  • \n
\n\n

الطريقة 2: forEachIndexed - بديل مدمج

\n\n

توفر Kotlin دالة جاهزة forEachIndexed، والتي تأخذ لامبدا بمعاملين: الفهرس والقيمة.

\n\n
list.forEachIndexed { index, value ->\n    println("الموضع $index: $value")\n}
\n\n

هذا تقريباً نفس withIndex().forEach، ولكن بدون استدعاء إضافي. هل يستخدم التنفيذ الداخلي لـ forEachIndexed أيضاً IndexedValue؟ لا، إنه يمرر الفهرس مباشرة، مما يجعله أسرع قليلاً.

\n\n

المزايا:

\n
    \n
  • أقصر كتابة ممكنة
  • \n
  • لا يوجد إنشاء كائنات وسيطة
  • \n
  • أسلوب Idiomatic في Kotlin
  • \n
\n\n

العيوب:

\n
    \n
  • أقل مرونة من withIndex() - لا يمكن دمجه مع عوامل تشغيل السلسلة الأخرى (مثل filter قبل forEach)
  • \n
\n\n

الطريقة 3: filterIndexed - عندما تحتاج إلى التصفية حسب الفهرس

\n\n

إذا كنت لا تحتاج فقط إلى الحصول على الفهرس، بل أيضاً إلى تصفية العناصر حسب موضعها، فإن filterIndexed هو خيارك.

\n\n
val list = listOf("a", "b", "c", "d", "e")\nval evenIndexed = list.filterIndexed { index, _ -> index % 2 == 0 }\nprintln(evenIndexed) // [a, c, e]
\n\n

لاحظ: المعامل الثاني هو العنصر نفسه، لكننا نتجاهله باستخدام _. هذه ممارسة قياسية في Kotlin للمتغيرات غير المستخدمة.

\n\n

المزايا:

\n
    \n
  • المرونة - يمكن دمج التصفية والتحويل
  • \n
  • أسلوب وظيفي نظيف
  • \n
\n\n

العي

المدونات

توصيات الكتب