مرتب سازی آرایه ها در PHP – به زبان ساده


دریافت اطلاعات خاص از میان دادههای مرتب شده همواره آسانتر است، چون در غیر این صورت برای به دست آوردن یک داده خاص باید همه عناصر آرایه مزبور یک به یک بررسی شوند. برای نمونه فرض کنید نمرات دانشجویان مختلف یک کلاس، در یک آرایه یا جدول ثبت شده باشند. اگر این دادهها بر اساس نمرات به دست آمده مرتب نشده باشند، باید پیش از آن که بتوانید بالاترین و پایینترین نمرههای کلاس را به دست آورید، تک تک نمرات دانشجویان را بررسی کنید. در صورتی که اگر جدول از قبل بر اساس نمرات کسب شده از پایین به بالا مرتب شده باشد، تنها با یک نگاه میتوان دانشجویی که پایینترین یا بالاترین نمره کلاس را کسب کرده شناسایی کرد. مرتبسازی باعث میشود بسیار از وظایفی که با بررسی و به دست آوردن مجموعه خاصی از دادهها مرتبط هستند آسان و کارآمد شود. در این راهنما به مرتبسازی آرایه ها در PHP با استفاده از تابعهای داخلی این زبان برنامهنویسی خواهیم پرداخت.
مرتبسازی آرایه بر اساس مقدار
در زبان برنامهنویسی PHP، مرتبسازی یک آرایه بر اساس مقدار عناصرش بسیار آسان است. هم میتوان از ارتباطهای کلید-مقدار استفاده کرد و هم این که تابعهایی برای تعیین شیوه مرتبسازی عناصر وجود دارند. در این بخش از راهنما روش انجام این کار را خواهیم دید.
میتوان از تابع (sort(&$array, $sort_flags برای مرتبسازی مقادیر یک آرایه از پایین به بالا استفاده کرد. با این وجود در این تابع اشارهای به ارتباطهای کلید-مقدار در هنگام مرتبسازی صورت نمیگیرد. در واقع به جای تغییر ترتیب ساده، کلیدهای جدیدی به عناصر مرتبسازی شده انتساب مییابند. پارامتر دوم که اختیاری است امکان تعیین چگونگی مرتبسازی عناصر را نیز در اختیار ما قرار میدهد. این پارامتر میتواند شش مقدار به صورت زیر داشته باشد:
- SORT_REGULAR - این پارامتر باعث مرتبسازی مقادیر بدون تغییر نوع آنها میشود.
- SORT_NUMERIC - این پارامتر موجب مرتبسازی مقادیر با مقایسه آنها به صورت عددی میشود.
- SORT_STRING - این پارامتر موجب مرتبسازی مقادیر بر اساس مقایسه آنها به صورت رشتهای میشود.
- SORT_LOCALE_STRING - این پارامتر موجب مقایسه مقادیر به صورت رشتهای بر اساس locale فعلی میشود. میتوانید locale را با استفاده از متد ()setlocale بهروزرسانی کنید.
- SORT_NATURAL - این پارامتر موجب مرتبسازی مقادیر با استفاده از «ترتیب طبیعی» (natural ordering) میشود و آنها را به صورت رشتهای مقایسه میکند.
- SORT_FLAG_CASE - این پارامتر موجب ترکیب با SORT_STRING یا SORT_NATURAL برای لغو اثر حساسیت به حروف کوچک و بزرگ در زمان مرتبسازی رشتهها میشود.
در ادامه چند نمونه از مرتبسازی برای آشنایی بیشتر شما با تفاوت بین روشهای مختلف مرتبسازی ارائه شده است:
<?php $random_data = [32508, 98134, "234984", "3249832", "38", 123, "Apple"]; sort($random_data); echo "Regular Sorting — "; foreach($random_data as $element) { echo str_pad($element, 9)." "; } // Regular Sorting — 38 123 32508 98134 234984 3249832 Apple sort($random_data, SORT_NUMERIC); echo "\nNumeric Sorting — "; foreach($random_data as $element) { echo str_pad($element, 9)." "; } // Numeric Sorting — Apple 38 123 32508 98134 234984 3249832 sort($random_data, SORT_STRING); echo "\nString Sorting — "; foreach($random_data as $element) { echo str_pad($element, 9)." "; } // String Sorting — 123 234984 3249832 32508 38 98134 Apple
در مثال نخست، مرتبسازی معمولی صورت میگیرد و رشتههای عددی به مقادیر عددی تبدیل میشوند و سپس بر همین اساس مرتبسازی میشوند. رشته «Apple» غیر عددی است و از این رو بدون تغییر میماند و به صورت یک رشته مقایسه میشود.
در مثال دوم که به مرتبسازی عددی مربوط است، میخواهیم دادهها بر اساس مقدار عددیشان مرتبسازی شوند و از این رو کلمه «Apple» به مقدار عددی 0 تبدیل میشود و در ابتدا میآید. باقی مقادیر نیز طبق انتظار مرتب شدهاند.
در مثال سوم، با همه مقادیر مانند رشته برخورد میکنیم. این بدان معنی است که به جای مقایسه مقدار عددی 123 یا 3249832 با 38، آنها را به صورت رشته با هم مقایسه میکنیم یعنی هر بار یک کاراکتر مقایسه میشود. از این رو «1» قبل از «3» میآید، و مقدار 123 کمتر از 38 در نظر گرفته میشود.
اگر بخواهید مقادیر آرایه را از بالا به پایین مرتبسازی کنید میتوانید به کمک تابع ()rsort این کار را انجام دهید. این تابع پارامترهایی مشابه تابع ()sort دارد؛ اما با ترتیب معکوس مرتبسازی میکند. همچنین به ارتباطهای کلید-مقدار اهمیتی نمیدهد و از این رو برای مرتبسازی «آرایههای انجمنی» (associative arrays) مناسب است.
مرتبسازی یک آرایه انجمنی
ارتباط کلید-مقدار زمانی که با آرایههای انجمنی سر و کار داریم بسیار اهمیت پیدا میکند. مثال زیر را در نظر بگیرید که یک آرایه انجمنی برای ذخیرهسازی نامهای افراد مختلف و میوههای مورد علاقهشان مورد استفاده قرار میگیرد. اگر بخواهیم این فهرست را بر مبنای حروف الفبای نام افراد یا میوهها مرتب کنیم؛ استفاده از تابع ()sort که در بخش قبل معرفی کردیم، موجب از بین رفتن ارتباط بین کلیدها میشود.
<?php $fruit_preferences = ["James" => "Orange", "John" => "Banana", "Patricia" => "Apple", "Jennifer" => "Mango", "Mary" => "Grapes"]; echo "Before Sorting — \n"; foreach($fruit_preferences as $person=>$preference) { echo $person." likes ".$preference."\n"; } /* Before Sorting — James likes Orange John likes Banana Patricia likes Apple Jennifer likes Mango Mary likes Grapes */ sort($fruit_preferences); echo "After Sorting — \n"; foreach($fruit_preferences as $person=>$preference) { echo $person." likes ".$preference."\n"; } /* After Sorting — 0 likes Apple 1 likes Banana 2 likes Grapes 3 likes Mango 4 likes Orange */ ?>
همان طور که میبینید ما نه تنها ارتباط افراد با میوههای مورد علاقهشان را از دست دادهایم؛ بلکه نامهای افراد مختلف نیز مفقود شدهاند. به هر مقدار مرتب شده یک اندیس جدید بر مبنای موقعیتش در آرایه مرتب شده انتساب مییابد.
برای کمک به حل این مشکل میتوان در PHP از تابعهای مختلفی استفاده کرد که ارتباط کلید-مقدار را در هنگام مرتبسازی آرایهها بر اساس مقدارشان حفظ میکند. این دو تابع ()asort و ()arsort هستند. در قطعه کد زیر همان آرایه fruit_preferences$ را مرتبسازی میکنیم؛ اما این بار بدین منظور از ()asort استفاده میکنیم:
<?php $fruit_preferences = ["James" => "Orange", "John" => "Banana", "Patricia" => "Apple", "Jennifer" => "Mango", "Mary" => "Grapes"]; echo "Before Sorting — \n"; foreach($fruit_preferences as $person=>$preference) { echo $person." likes ".$preference."\n"; } /* Before Sorting — James likes Orange John likes Banana Patricia likes Apple Jennifer likes Mango Mary likes Grapes */ asort($fruit_preferences); echo "After Sorting — \n"; foreach($fruit_preferences as $person=>$preference) { echo $person." likes ".$preference."\n"; } /* After Sorting — Patricia likes Apple John likes Banana Mary likes Grapes Jennifer likes Mango James likes Orange */ ?>
همان طور که در مثال فوق مشخص است، مقدار Apple به بالا انتقال میآید و با این حال همچنان ارتباط خود را با Patricia حفظ کرده است. نامهای میوهها را میتوانستیم با کمک تابع ()arsort با ترتیب معکوس نیز مرتبسازی کنیم.
هر دو این تابعها همان فلگهای مرتبسازی به عنوان پارامترهای دوم اختیاری مانند تابعهای ()sort و ()rsort را میپذیرند.
مرتبسازی عناصر آرایه بر اساس مقدار با تابعهای تعریف شده از سوی کاربر
چهار تابع مرتبسازی که در بخشهای قبل معرفی کردیم، میتوانند به سادگی نیازهای رایج مرتبسازی را به کمک فلگهای مختلف تأمین کنند. با این وجود در برخی موارد، معیارهای برنامهنویس برای مقایسه عناصر آرایه ممکن است متفاوت باشد.
برای مثال تصور کنید آرایهای از کلمههای تصادفی دارید که باید بر اساس حروف الفبا مرتبسازی شوند. با این وجود شما میخواهید که آنها را قبل از مرتبسازی بر اساس حروف الفبا بر مبنای طولشان نیز مرتبسازی کنید. برای نمونه در مرتبسازی معمولی الفبایی، zoo باید پس از apple بیاید. اما اگر بخواهیم کلمههای کوتاه قبل از کلمههای بلند بیایند در این صورت zoo پس از apple قرار میگیرد. اگر تعداد حروف را یکسان بگیریم میبینیم که ape به دلیل ترتیب الفبایی باید قبل از zoo بیاید.
در واقع کلمهها در ابتدا بر اساس طولشان مرتب میشوند و سپس برحسب تعداد حروف یکسان بر مبنای ترتیب الفبایی در گروه خود مرتبسازی میشوند. این نوع مرتبسازی با استفاده از تابعهای درونی PHP ممکن نیست و از این رو باید تابع مرتبسازی خاص خود را به این منظور بنویسیم.
کاری که PHP در این مورد انجام میدهد، ارائه چند تابع است که میتوانند برای ارسال آرایهای که میخواهیم مرتبسازی کنیم به همراه نام تابع مرتبسازی سفارشی، مورد استفاده قرار گیرند.
در آرایههای معمولی میتوان از تابع ()usort برای مرتبسازی مقادیر آرایه استفاده کرد. به طور مشابه میتوان از تابع ()uasort برای مرتبسازی مقادیر در آرایههای انجمنی استفاده کرد و ارتباطهای کلید-مقدار را نیز در آنها حفظ نمود.
قطعه کد زیر یکی از روشهای ممکن برای اجرای هدف فوق را نشان میدهد.
<?php $random_words = ["ape", "apple", "zoo", "pie", "elephant", "banana", "picnic", "eye"]; sort($random_words); echo "Regular Sort Function: \n"; foreach($random_words as $element) { echo str_pad($element, 9)." "; } /* Regular Sort Function: ape apple banana elephant eye picnic pie zoo */ function custom_sort($word_a, $word_b) { if (strlen($word_a) < strlen($word_b)) { return -1; } if (strlen($word_a) == strlen($word_b)) { return strcmp($word_a, $word_b); } if (strlen($word_a) > strlen($word_b)) { return 1; } } usort($random_words, "custom_sort"); echo "\nCustom Sort Function: \n"; foreach($random_words as $element) { echo str_pad($element, 9)." "; } /* Custom Sort Function: ape eye pie zoo apple banana picnic elephant */ ?>
در تابعهای callback که برای مرتبسازی سفارشی نوشته شدهاند، باید یک عدد صحیح کمتر از 1- بازگردانیم تا نشان دهیم که مقدار نخست کوچکتر از مقدار دوم است. بازگشت مقدار 0 به این معنی است که هر دو مقدار برابر هستند و بازگشت دادن مقدار 1 نشان میدهد که مقدار اول بزرگتر از مقدار دوم است.
از آنجا که معیار اصلی مرتبسازی ما طول رشته است، در صورتی که کلمه اول کوتاهتر از کلمه دوم باشد، میتوانیم مستقیماً مقدار 1- را باز گردانیم. به طور مشابه اگر کلمه اول طولانیتر از کلمه دوم باشد، میتوانیم مستقیماً مقدار 1 را بازگشت دهیم. اگر طول دو کلمه با هم برابر باشند، آنها را با استفاده از تابع ()strcmp به صورت الفبایی مقایسه میکنیم و نتیجه را بازگشت میدهیم.
همان طور که در خروجی مشاهده میکنید، تابع مرتبسازی سفارشی ما کلمهها را دقیقاً آن چنان که انتظار داریم مقایسه میکند.
مرتبسازی یک آرایه بر اساس مقدار
مرتبسازی یک آرایه بر اساس کلیدهای آن به طور کلی زمانی مفید است که با آرایههای انجمنی سر و کار داشته باشیم.
برای نمونه ممکن است آرایهای داشته باشید که شامل اطلاعاتی در مورد تعداد کلی فرودگاهها در کشورهای مختلف باشد. با فرض این که نامهای کشورهای مختلف، کلید و تعداد فرودگاهها مقدارهای ما باشند، اگر بخواهیم نام کشورها را به صورت الفبایی مرتب کنیم، میتوانیم با بهرهگیری از تابعهای ()ksort و ()krsort این کار را بسیار به سادگی انجام دهیم. هر دو این توابع ارتباط بین کلید-مقدار را پس از مرتبسازی حفظ میکنند. تابع ()ksort کلیدها را از پایین به بالا و ()krsort نیز کلیدها را از بالا به پایین مرتبسازی میکند. در ادامه مثالی از یک مرتبسازی ساده را مشاهده میکنید.
<?php $airport_count = ["United States" => 13513, "Brazil" => 4093, "Mexico" => 1714, "Canada" => 1467, "Russia" => 1218, "Argentina" => 1138, "Bolivia" => 855, "Colombia" => 836, "Paraguay" => 799, "Indonesia" => 673]; ksort($airport_count); foreach($airport_count as $country=>$count) { echo str_pad($country, 15)." ".$count."\n"; } /* Argentina 1138 Bolivia 855 Brazil 4093 Canada 1467 Colombia 836 Indonesia 673 Mexico 1714 Paraguay 799 Russia 1218 United States 13513 */ ?>
همچنین میتوانید تابع سفارشی خاص خود را برای مرتبسازی کلیدهای آرایه با بهرهگیری از تابع ()uksort در PHP بنویسید. همانند تابع ()usort، تابع callback در ()uksort در صورت کوچکتر بودن کلید اول از کلید دوم یک عدد صحیح کمتر از 0 بازگشت میدهد. همچنین در مواردی که کلید اول و دوم برابر باشند، مقدار 0 و در مواردی که کلید اول بزرگتر از کلید دوم باشد، عددی بزرگتر از 0 بازگشت مییابد. این تابع همچنین ارتباط کلید-مقدار را در عناصر آرایه حفظ میکند.
<?php $airport_count = ["United States" => 13513, "Brazil" => 4093, "Mexico" => 1714, "Canada" => 1467, "Russia" => 1218, "Argentina" => 1138, "Bolivia" => 855, "Colombia" => 836, "Paraguay" => 799, "Indonesia" => 673]; function custom_sort($word_a, $word_b) { if (strlen($word_a) < strlen($word_b)) { return -1; } if (strlen($word_a) == strlen($word_b)) { return strcmp($word_a, $word_b); } if (strlen($word_a) > strlen($word_b)) { return 1; } } uksort($airport_count, "custom_sort"); foreach($airport_count as $country=>$count) { echo str_pad($country, 15)." ".$count."\n"; } /* Brazil 4093 Canada 1467 Mexico 1714 Russia 1218 Bolivia 855 Colombia 836 Paraguay 799 Argentina 1138 Indonesia 673 United States 13513 */ ?>
در مثال فوق ما از تابع مرتبسازی سفارشی بخش قبلی برای مرتب کردن نامهای کشورها ابتدا بر اساس طول نامهایشان و سپس بر اساس ترتیب حروف الفبا استفاده کردهایم.
مرتبسازی آرایههای چندبعدی در PHP
ما در زندگی روزمره خود به طور مکرر با آرایهای چندبعدی سر و کار داریم. برای نمونه مؤسسات آموزشی مختلف به جای این که نمرات دانشجویانشان را در موضوعات مختلف، در جدولهای منفرد نگهداری کنند؛ برای هر دانشجو یک جدول تشکیل میدهند و همه نمرههای وی را در آنجا ذخیره میسازند. اگر مجبور باشید اطلاعات یکسانی را در PHP ذخیره کنید، ممکن است ترجیح بدهید که این کار را به جای استفاده از آرایههای مجزا برای هر موضوع، با استفاده از آرایه چندبعدی صورت بدهید.
در این راهنما با روش مرتبسازی آرایههای چندبعدی با استفاده از مثالی به صورت یک فهرست از بلندترین برجهای جهان آشنا میشویم. آرایه ما شامل اطلاعاتی در مورد نام این ساختمانها، شهر و کشوری که در آن قرار دارند، تعداد طبقهها، ارتفاع کلی برحسب متر و همچنین سالی که ساخته شدهاند است.
زمانی که میخواهیم مقادیر را در یک آرایه چندبعدی بر اساس فیلد خاصی مرتبسازی کنیم میتوانیم به سادگی از تابع ()usort استفاده کنیم. مثال زیر به درک بهتر این مسئله کمک میکند.
<?php $tallest_buildings = [ ["Building" => "Burj Khalifa","City" => "Dubai","Country" => "United Arab Emirates","Height" => 828,"Floors" => 163,"Year" => 2010], ["Building" => "Shanghai Tower","City" => "Shanghai","Country" => "China","Height" => 632,"Floors" => 128,"Year" => 2015], ["Building" => "Abraj Al-Bait Towers","City" => "Mecca","Country" => "Saudi Arabia","Height" => 601,"Floors" => 120,"Year" => 2012], ["Building" => "Ping An Finance Center","City" => "Shenzhen","Country" => "China","Height" => 599,"Floors" => 115,"Year" => 2017], ["Building" => "Lotte World Tower","City" => "Seoul","Country" => "South Korea" ,"Height" => 554,"Floors" => 123,"Year" => 2016] ]; function storey_sort($building_a, $building_b) { return $building_a["Floors"] - $building_b["Floors"]; } usort($tallest_buildings, "storey_sort"); foreach($tallest_buildings as $tall_building) { list($building, $city, $country, $height, $floors) = array_values($tall_building); echo $building." is in ".$city.", ".$country.". It is ".$height." meters tall with ".$floors." floors.\n"; } /* Ping An Finance Center is in Shenzhen, China. It is 599 meters tall with 115 floors. Abraj Al-Bait Towers is in Mecca, Saudi Arabia. It is 601 meters tall with 120 floors. Lotte World Tower is in Seoul, South Korea. It is 554 meters tall with 123 floors. Shanghai Tower is in Shanghai, China. It is 632 meters tall with 128 floors. Burj Khalifa is in Dubai, United Arab Emirates. It is 828 meters tall with 163 floors. */ ?>
در مثال فوق، اطلاعات مربوط به هر ساختمان در آرایه خاصی درون آرایه اصلی tallest_buildings$ ذخیره شده است. تابع ()storey_sort به سادگی تعداد طبقات در ساختمان دوم را از اولی کم میکند و بر اساس معیار ما تعیین میکند که کدام ساختمان کوچکتر است. لازم نیست در مورد بازگشت مقدار منفی یا مثبت نگران باشیم، چون در این روش مقادیر منفی به معنی کوچکتر هستند و مقادیر مثبت یعنی ساختمان بزرگتر است.
در نهایت کافی است حلقهای روی آرایه اصلی تعریف کنیم و اطلاعات مربوط به هر ساختمان را نمایش دهیم.
سخن پایانی
در این راهنما تابعهای مختلف PHP را که میتوان برای مرتبسازی آرایهها بر اساس کلید یا مقدارهایشان استفاده کرد را نشان دادهایم. همچنین در مورد چگونگی مرتبسازی یک آرایه بر اساس کلید یا مقدار و نوشتن تابعهای مرتبسازی سفارشی به کمک تابعهای ()uksort و ()uasort نکاتی آموختیم. در بخش انتهایی این مقاله به بررسی چگونگی مرتبسازی مقادیر در آرایههای چندبعدی با استفاده از صرفاً یک فیلد خاص پرداختیم.
امیدواریم از این مقاله نکات جدید و مفیدی آموخته باشید. هر گونه سؤال یا پیشنهاد خود را میتوانید در بخش نظرات این نوشته با ما و دیگر خوانندگان فرادرس در میان بگذارید. بهترین روش برای یادگیری، تکرار و تمرین و حل مثالهای مختلف است. بنابراین تلاش کنید مسائل مختلفی در رابطه با مرتبسازی آرایه طرح کرده و حل کنید.
اگر این نوشته برای شما مفید بوده است، پیشنهاد ما استفاده از آموزشهای زیر است:
- مجموعه آموزشهای برنامهنویسی PHP
- مجموعه آموزشهای برنامهنویسی
- مجموعه آموزشهای مهندسی نرم افزار
- برنامهنویسی PHP و هر آنچه برای شروع باید بدانید — آموزش جامع
- آموزش فریمورک لاراول PHP Laravel برای ساخت فروشگاه اینترنتی
- آرایه های PHP — به زبان ساده
==