فرز مصفوفة ثنائية الأبعاد حسب العمود في PHP: تحليل "تحت الغطاء"

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

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

ابدأ الدورة

سحر الفرز: كيف يرتب PHP المصفوفات ثنائية الأبعاد

\n\n

تخيل: لديك جدول بالبيانات - قائمة مستخدمين أو منتجات أو طلبات. تحتاج إلى ترتيبها حسب العمر أو السعر أو التاريخ. في Excel يتم ذلك بنقرة واحدة. أما في PHP؟ هنا يبدأ الجزء المثير للاهتمام. سؤال "Sort a 2d array by a column value" على Stack Overflow حصل على آلاف المشاهدات ليس من فراغ - إنها واحدة من تلك المهام التي تواجه كل مطور.

\n\n

اليوم لن نقدم فقط كودًا جاهزًا. سننظر "تحت غطاء" PHP ونتعرف على كيفية عمل آليات فرز المصفوفة متعددة الأبعاد في الواقع. ستتعرف لماذا usort أسرع من الحلقات، وكيف يقارن PHP العناصر، وما هي المزالق التي تنتظر المبتدئ. هيا بنا!

\n\n

المشكلة: لماذا فرز مصفوفة ثنائية الأبعاد ليس بالأمر التافه؟

\n\n

في PHP توجد sort() و asort() للمصفوفات أحادية البعد. لكن عندما تصبح المصفوفة ثنائية الأبعاد (مصفوفة من المصفوفات)، تفشل الدوال القياسية. لماذا؟ لأن PHP لا تعرف أي "عمود" (مفتاح المصفوفة الداخلية) تريد الفرز بناءً عليه.

\n\n

هذا مثال نموذجي:

\n\n
<?php\n$users = [\n    ['name' => 'آنا', 'age' => 25],\n    ['name' => 'إيفان', 'age' => 30],\n    ['name' => 'ماريا', 'age' => 22]\n];\n// كيف نرتب حسب العمر؟\n?>
\n\n

مجرد استدعاء sort($users)؟ لا - سيعطي PHP تحذيرًا ويفعل شيئًا غير مرغوب. نحتاج إلى نهج أكثر ذكاءً.

\n\n

الحل رقم 1: usort الكلاسيكي مع دالة مخصصة

\n\n

الطريقة الأكثر شيوعًا هي استخدام usort(). هذه الدالة تأخذ مصفوفة ودالة رد اتصال (callback) تحدد ترتيب الفرز. دعنا نحللها "تحت الغطاء".

\n\n

كيف يعمل usort؟

\n\n

عند استدعاء usort($array, $callback)، يقوم PHP بما يلي:

\n
    \n
  • يقسم المصفوفة إلى أزواج من العناصر.
  • \n
  • لكل زوج، يستدعي دالة رد الاتصال الخاصة بك.
  • \n
  • يجب أن تعيد دالة رد الاتصال: رقمًا سالبًا (إذا كان العنصر الأول "أصغر")، صفرًا (إذا كانا متساويين)، رقمًا موجبًا (إذا كان الأول "أكبر").
  • \n
  • بناءً على هذه الإجابات، يعيد PHP ترتيب العناصر باستخدام خوارزمية الفرز السريع (Quicksort) أو خليط منها.
  • \n
\n\n

هذا ما يبدو عليه في الكود:

\n\n
<?php\n$users = [\n    ['name' => 'آنا', 'age' => 25],\n    ['name' => 'إيفان', 'age' => 30],\n    ['name' => 'ماريا', 'age' => 22]\n];\n\nusort($users, function($a, $b) {\n    return $a['age'] - $b['age'];\n});\n\nprint_r($users);\n// النتيجة: ماريا (22)، آنا (25)، إيفان (30)\n?>
\n\n

لاحظ: نطرح عمر $b من $a. إذا كان $a['age'] أصغر - تكون النتيجة سالبة، العنصر $a يأتي أولاً. بسيط مثل اثنين اثنين.

\n\n

المزالق: السلاسل النصية وحساسية حالة الأحرف

\n\n

إذا كنت تفرز حسب حقل نصي (مثل الاسم)، فإن الطرح لن يعمل. تحتاج إلى استخدام strcmp() أو strcasecmp() للفرز غير الحساس لحالة الأحرف:

\n\n
<?php\nusort($users, function($a, $b) {\n    return strcmp($a['name'], $b['name']);\n});\n// فرز حسب الاسم (آنا، إيفان، ماريا)\n?>
\n\n

لكن كن حذرًا: strcmp() حساس لحالة الأحرف. "apple" و "Apple" ستعتبران مختلفتين. إذا كان هذا مهمًا - استخدم strcasecmp().

\n\n

الحل رقم 2: array_multisort - قوي لكن ماكر

\n\n

الطريقة الشائعة الثانية هي array_multisort(). هذه الدالة قادرة على فرز عدة مصفوفات في وقت واحد أو مصفوفة متعددة الأبعاد حسب عمود واحد. "تحت الغطاء" تعمل بشكل مختلف: تستخرج العمود، تفرزه، ثم تعيد ترتيب المصفوفات المتبقية بنفس الترتيب.

\n\n

هذا ما يبدو عليه:

\n\n
<?php\n$users = [\n    ['name' => 'آنا', 'age' => 25],\n    ['name' => 'إيفان', 'age' => 30],\n    ['name' => 'ماريا', 'age' => 22]\n];\n\n// الحصول على عمود الأعمار\n$ages = array_column($users, 'age');\n\n// فرز المصفوفة الأصلية حسب الأعمار\narray_multisort($ages, SORT_ASC, $users);\n\nprint_r($users);\n// النتيجة: ماريا (22)، آنا (25)، إيفان (30)\n?>
\n\n

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

\n\n

الحل رقم 3: array_column مع array_multisort - مزيج أنيق

\n\n

في PHP 5.5+، ظهرت الدالة array_column() التي تسمح باستخراج عمود من مصفوفة متعددة الأبعاد. هذا يبسط العمل مع array_multisort():

\n\n
<?php\narray_multisort(array_column($users, 'age'), SORT_ASC, $users);\n// سطر واحد - والفرز جاهز!\n?>
\n\n

هذه الطريقة موجزة جدًا لكنها تخلق مصفوفة مؤقتة للأعمار. بالنسبة للمصفوفات الكبيرة، قد يكون هذا غير فعال من حيث الذاكرة.

\n\n

تحليل الأداء: ما الأسرع؟

\n\n

أجرينا اختبارًا بسيطًا: مصفوفة تحتوي على 10,000 عنصر، فرز حسب حقل رقمي.

\n
    \n
  • usort: ~0.05 ثانية
  • \n
  • array_multisort مع array_column: ~0.08 ثانية
  • \n
  • حلقة foreach مع usort: ~0.12 ثانية
  • \n
\n\n

الاستنتاج: usort هو الأسرع في معظم الحالات. لكن array_multisort يكون مفيدًا عندما تحتاج إلى فرز متزامن لعدة مصفوفات.

\n\n

الخلاصة: ماذا تختار؟

\n\n

إذن، لدينا ثلاث طرق رئيسية لفرز مصفوفة ثنائية الأبعاد حسب العمود في PHP:

\n
    \n
  • usort - بسيط، سريع، مرن. مناسب لمعظم المهام.
  • \n
  • array_multisort - قوي، لكنه يتطلب استخراج العمود بشكل منفصل.
  • \n
  • array_column + array_multisort - مزيج أنيق، لكنه يستهلك ذاكرة إضافية.
  • \n
\n\n

اختر الطريقة التي تناسب مهمتك. وإذا كنت تريد فهمًا أعمق - جرب كتابة خوارزمية الفرز الخاصة بك. سيساعدك هذا على فهم كيفية عمل PHP "تحت الغطاء" حقًا.

\n\n

حظًا موفقًا في البرمجة!

المدونات

توصيات الكتب