Menu
flag Ar iconالعربيةdown icon

الشرط if وelse في R: ‏if وelse if وifelse() وswitch()

المنطق الشرطي في R - صياغة if/else if/else، وفخ الأقواس المعقوفة الذي يعطّل النصوص البرمجية، وifelse() المتجهية للمتجهات الكاملة، وswitch() للاختيارات متعددة المسارات.

تحتوي هذه الصفحة على محررات قابلة للتشغيل - حرّر، شغّل، وشاهد النتيجة فوراً.

تعليمة if

تنفّذ تعليمة if في R كتلة من الشيفرة فقط حين يكون الشرط TRUE. ويوضع الشرط بين قوسين، والشيفرة بين أقواس معقوفة، وتوفر else الاختيارية ما يحدث خلاف ذلك:

يُقيَّم الشرط score >= 60 إلى قيمة TRUE واحدة، فيُنفَّذ الفرع الأول. ومعاملات المقارنة والمنطق - مثل == و>= و&& و%in% وأخواتها - هي ما تبني منه هذه الشروط.

ولأكثر من نتيجتين، تسلسل الفحوص بـ else if. وتمشي R في السلسلة بدءًا من الشرط الأول وتنفّذ أول فرع يتحقق شرطه، متخطية ما تبقى:

والترتيب مهم: فلأن الشرط 85 >= 80 يُفحص قبل 85 >= 70، تكون الدرجة "B". ولو رتبت الفحوص بالعكس لحصلت كل درجة تفوق 70 على التقدير "C".

فخ الأقواس المعقوفة: أين يجب أن تقع else

هذا هو الخطأ الذي يلدغ أول نص برمجي بلغة R لدى الجميع تقريبًا. ففي النص البرمجي (أو في أي شيء يُشغَّل عبر Rscriptيجب أن تظهر else في السطر نفسه مع القوس المغلق للفرع الذي يسبقها. وهذا يفشل:

if (score >= 60) {
  print("You passed")
}
else {              # Error: unexpected 'else'
  print("Try again")
}

والسبب: تحلل R تعليمة تلو الأخرى. فحين تصل إلى القوس } في مستهل سطر، تكون تعليمة if مكتملة نحويًا، فتقيّمها R عندئذ وهناك. وتصل else في السطر التالي بوصفها بداية تعليمة جديدة - ولا يمكن أن تبدأ تعليمة بالكلمة else. والحل هو النمط المستخدم في هذه الصفحة كلها:

if (score >= 60) {
  print("You passed")
} else {            # brace and else on the same line
  print("Try again")
}

وداخل جسم دالة أو أي مجموعة أقواس معقوفة محيطة تتراخى القاعدة الصارمة (إذ تواصل R القراءة حتى يُغلق القوس المحيط)، لكن لا تعتمد على ذلك - فأسلوب } else { يعمل في كل مكان وهو ما توصي به أدلة تنسيق R.

يجب أن يكون الشرط قيمة TRUE أو FALSE واحدة

تطلب if() قيمة منطقية واحدة بالضبط. وثمة أمران يخالفان ذلك، وكلاهما خطأ:

if (NA) print("hi")
# Error: missing value where TRUE/FALSE needed

if (c(TRUE, FALSE)) print("hi")
# Error: the condition has length > 1

وحالة NA مهمة عمليًا لأن المقارنات مع البيانات المفقودة تنتج قيمة NA: فإذا كانت x تساوي NA، فإن x > 10 تساوي NA، وتعليمة if التي تتلقى ذلك الشرط توقف نصك البرمجي. والنمط الدفاعي يستخدم المعامل && المقصّر للدارة:

ولأن !is.na(x) تساوي FALSE، لا يُقيَّم الجزء x > 10 أبدًا ولا تصل أي قيمة NA إلى الشرط. وكيفية انتشار NA عبر المقارنات مشروحة في القيم المفقودة.

أما خطأ الطول الأكبر من واحد (المفروض منذ الإصدار R 4.2؛ وقبله كانت R تستخدم العنصر الأول بصمت) فيعني عادة أنك قصدت أحد هذه البدائل: any(v > 5) إذا كانت مطابقة واحدة كافية، أو all(v > 5) إذا وجب أن يجتاز كل عنصر الفحص، أو ifelse() إذا أردت جوابًا لكل عنصر - وهو موضوع القسم التالي.

‏ifelse(): الشرط المتجهي

تقرر if مرة واحدة. أما ifelse(test, yes, no) فتقرر لـ كل عنصر في المتجه وتعيد متجهًا بالطول نفسه:

يُختبر كل عنصر في temps باستقلال: ‏"hot" "mild" "mild" "hot" "mild". وهذه هي الأداة لاشتقاق متجه جديد أو عمود جديد في إطار بيانات انطلاقًا من آخر موجود - دون أي حلقة.

وبخلاف if، تتعامل ifelse() مع القيم المفقودة بلباقة: فقيمة NA في الاختبار تعطي NA في النتيجة بدل إطلاق خطأ:

ويمكنك تعشيش استدعاءات ifelse() لتقسيم ثلاثي، وعند هذا العمق تبقى الشيفرة مقروءة:

لكن قف عند هذا الحد. فثلاثة استدعاءات متداخلة أو أكثر من ifelse() تتحول إلى أحجية مطابقة أقواس؛ وعندها الجأ إلى cut() (للنطاقات العددية) أو dplyr::case_when() التي تضع كل شرط في سطر مستقل.

الدالة switch() للاختيارات متعددة المسارات

حين تطابق قيمة واحدة مع قائمة من الأسماء المعروفة - لا حين تختبر نطاقات - تكون سلسلة else if الطويلة أداة خرقاء. أما switch() فتقول ذلك مباشرة:

وثمة ثلاثة سلوكيات ينبغي معرفتها:

  • المطابقة: تقارن switch() القيمة النصية بأسماء الوسائط وتعيد النتيجة المطابقة.
  • السقوط: الاسم الذي يخلو طرفه الآخر من قيمة (sat = ,) يسقط إلى نتيجة الحالة التالية - وهكذا تتشارك القيمتان "sat" و"sun" النتيجة "weekend" دون تكرارها.
  • القيمة الافتراضية: يُعاد الوسيط الأخير غير المسمى ("weekday") حين لا تطابق أي حالة. وبدون قيمة افتراضية، تجعل القيمة غير المطابقة switch() تعيد NULL بصمت - فتعيد دالتك لا شيء بهدوء، وهي علة محيرة. وفّر دائمًا قيمة افتراضية (أو اجعلها استدعاء stop() صريحًا).

وتتألق switch() داخل الدوال التي ترسل التنفيذ بحسب وسيط للنمط أو الأسلوب؛ أما لأي شيء مبني على عتبات عددية، فالتزم بـ else if أو cut().

ما تخرج به

  • الصيغة if (condition) { } else { } - الشرط بين قوسين، وينفَّذ فرع واحد؛ وتسلسلها بـ else if، وأول مطابقة تفوز.
  • في النصوص البرمجية، اكتب } else { في سطر واحد - فوجود else في مستهل سطر خطأ نحوي.
  • تحتاج if() إلى قيمة TRUE/FALSE واحدة بالضبط: فالقيمة NA خطأ، والمتجه الأطول خطأ (منذ الإصدار R 4.2). احرس الشرط بـ !is.na(x) &&، أو اختزله بـ any()/all().
  • الدالة ifelse(test, yes, no) هي النسخة المتجهية - استخدمها لحساب متجهات جديدة، ولا تعشّشها أكثر من مرتين.
  • تتولى switch() الإرسال متعدد المسارات وفق الأسماء، مع السقوط عبر الحالات الفارغة - وامنحها دائمًا قيمة افتراضية.

التالي: فعل شيء أكثر من مرة - حلقات for، ومتى تكون الحلقة الأداة الصحيحة ومتى لا تكون.

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

كيف تكتب تعليمة if else في R؟

بالصيغة if (condition) { ... } else { ... } - إذ يوضع الشرط بين قوسين وكل فرع بين أقواس معقوفة. وتسلسل الفحوص الإضافية بـ else if (condition). وفي النص البرمجي، يجب أن تقع else في السطر نفسه مع القوس المغلق للفرع السابق (} else {)، وإلا أبلغت R عن الخطأ unexpected 'else'.

ما الفرق بين if وifelse() في R؟

التعليمة if تعليمة تحكم في التدفق تختبر قيمة TRUE/FALSE واحدة بالضبط وتنفّذ فرعًا واحدًا من الشيفرة. أما ifelse(test, yes, no) فدالة متجهية: تختبر كل عنصر في المتجه دفعة واحدة وتعيد متجهًا من النتائج. استخدم if لتقرير ما يفعله برنامجك؛ واستخدم ifelse() لحساب عمود أو متجه جديد انطلاقًا من آخر موجود.

لماذا تقول R إن 'the condition has length > 1'؟

لأنك مررت متجهًا كاملًا إلى if() التي تحتاج إلى قيمة TRUE أو FALSE واحدة. ومنذ الإصدار R 4.2 صار هذا خطأ بدل الاستخدام الصامت للعنصر الأول. أصلحه باختزال المتجه إلى قيمة واحدة - عبر any(x > 5) أو all(x > 5) - أو بالانتقال إلى ifelse() المتجهية إن كنت تريد نتيجة لكل عنصر.

كيف تعمل switch() في R؟

تقارن switch(value, name1 = result1, name2 = result2, default) قيمة نصية بأسماء الوسائط وتعيد النتيجة المطابقة. والاسم الذي يخلو طرفه الآخر من قيمة يسقط إلى النتيجة التالية، فتتشارك عدة حالات نتيجة واحدة. ويعمل الوسيط الأخير غير المسمى بوصفه القيمة الافتراضية؛ وبدونه تعيد القيمة غير المطابقة NULL بصمت.

Coddy programming languages illustration

تعلّم البرمجة مع Coddy

ابدأ الآن