PDA

View Full Version : سوال: سخت جایگشت با آرایه ها



mamali-mohammad
جمعه 07 آبان 1395, 20:05 عصر
سلام
فرض کنیم 3 تا آرایه داریم

$one = array('a','b');$two = array('x','y');$three = array('1');
حالا خروجی زیر رو می خوایم

ax1ay1bx1by1فقط مسئله مهم اینه از foreach نمی خوام استفاده کنم
چون تعداد آرایه ها و محتواش ممکنه تغییر کنه
ممنون

-سیّد-
شنبه 08 آبان 1395, 16:35 عصر
سلام
۲ تا راه حل برای این مسئله به نظرم می‌رسه. یکی بازگشتی، دومی غیر بازگشتی. البته می‌دونید که، هر مسئلهٔ بازگشتی‌ای رو می‌شه به صورت غیر بازگشتی هم حل کرد.
چیزی که توی هر دوتای این راه‌حل‌ها مشترکه، اینه که شما یه آرایه از این آرایه‌ها باید داشته باشید:


$arrays = [$one, $two, $three];

(یه نکته هم توی پرانتز بگم: از php نسخهٔ 5.4 می‌تونید از علامت [] به جای ()array برای ساختن آرایه‌ها استفاده کنید:
http://ir.php.net/manual/en/language.types.array.php


As of PHP 5.4 you can also use the short array syntax, which replaces array() with [].


)
حالا اگه خواستید آرایهٔ دیگه‌ای اضافه کنید، توی همین آرایه اضافه می‌کنید.

راه بازگشتی:
یه تابع بازگشتی به این صورت می‌نویسید:


function f($arrays, $current = 0, &$str = '') {
...
}

پارامترها:

$arrays: فهرست آرایه‌ها
$current: شمارهٔ آرایه‌ای که الان باید پردازش بشه
$str: رشته‌ای که در حال ساخته شدن هست و توی خروجی چاپ می‌شه


توی تابع، آرایهٔ شمارهٔ current$ رو بر می‌دارید، یه foreach روی تمامی مقادیرش می‌ذارید، داخلش خونهٔ شمارهٔ current$ رشتهٔ str$ رو با مقدار فعلی آرایه (که روش foreach زدید) جایگزین می‌کنید، و بعد در صورتی که این آرایه آخرین آرایهٔ فهرست آرایه‌ها باشه، رشتهٔ str$ رو چاپ می‌کنید. در غیر این صورت، تابع f رو به صورت بازگشتی به صورت زیر فراخوانی می‌کنید:


f($arrays, $current + 1, $str);


در نهایت هم توی بخش اصلی کد، تابع f رو با پارامتر arrays$ فراخوانی می‌کنید که کار شروع بشه.
یه نکته‌ای که توی این راه‌حل هست، اینه که فرض کردم هر کدوم از خونه‌های آرایه‌ها، یک کاراکتر بیشتر نیستن. اگه بیشتر هستن، به جای اون رشتهٔ str$، می‌تونید از یک آرایه استفاده کنید و موقع چاپ خونه‌هاش رو implode کنید. یا می‌تونید رشته رو با reference پاس نکنید به تابع، و از روی رشتهٔ ورودی یه کپی بسازید، و بعد خونهٔ مورد نظر آرایه رو به اون کپی append کنید و پاس کنید به فراخوانی بعدی تابع.

راه غیر بازگشتی:
یه آرایهٔ دیگه می‌سازید به نام indices$، که توش به ازای هر یک از این آرایه‌ها، یه خونه هست که نشون‌دهندهٔ index فعلی پردازش‌شدهٔ آرایهٔ متناظرش هست، و در ابتدا مقدار همهٔ خونه‌هاش صفره:


$indices = array_fill(0, count($arrays, 0);

بعد، یه حلقهٔ while رو شروع می‌کنید با یک شرط finished$ که در ابتدا مقدارش false هست. توی حلقه، اول یه for روی آرایهٔ arrays$ می‌ندازید، به ازای هر خونه، خونهٔ متناظرش توی آرایهٔ indices$ رو پیدا می‌کنید (n)، و بعد خونهٔ شمارهٔ n رو چاپ می‌کنید. با این کار، خروجی متناظر این دور از عملیات چاپ می‌شه. بعد، آخرین خونهٔ آرایهٔ indices$ رو بررسی می‌کنید. در صورتی که مقدارش برابر طول آرایهٔ متناظرش توی آرایهٔ arrays$ نبود، یکی زیادش می‌کنید و به ابتدای حلقه بر می‌گردید. در صورتی که به اون طول رسیده بود، مقدارش رو صفر می‌کنید، و بعد خونهٔ قبلیش رو به همین صورت چک می‌کنید. در صورتی که تمام خونه‌ها رو چک کردید و همه‌شون به آخرشون رسیده بودن و به اولین خونه رسیدید، و اون هم به آخرین خونه‌اش رسیده بود، کار تموم می‌شه و finished رو برابر true می‌کنید که از حلقهٔ اصلی بیرون بیایم و کار تموم بشه.
ترتیب اجراش اینجوری می‌شه:


$arrays = [[a, b], [x, y], [1]]
$indices = [0, 0, 0]
loop1:
print
=> ax1
check
$current = last element = count($arrays) = 2
loop2:
$indices[$current] == 0
count($arrays[$current]) - 1 = 0
=> 0 == 0
=> set $indices[$current] = 0
=> $indices = [0, 0, 0]
=> try next element: $current--
=> $current = 1
=> is $current == -1? no => continue
$indices[$current] == 0
count($arrays[$current]) - 1 = 1
=> 0 < 1
=> $indices[$current]++
=> $indices = [0, 1, 0]
=> exit loop2
loop1:
print
=> ay1
check
$current = last element = count($arrays) = 2
loop2:
$indices[$current] == 0
count($arrays[$current]) - 1 = 0
=> 0 == 0
=> set $indices[$current] = 0
=> $indices = [0, 1, 0]
=> try next element: $current--
=> $current = 1
=> is $current == -1? no => continue
$indices[$current] == 1
count($arrays[$current]) - 1 = 1
=> 1 == 1
=> set $indices[$current] = 0
=> $indices = [0, 0, 0]
=> try next element: $current--
=> $current = 0
=> is $current == -1? no => continue
$indices[$current] == 0
count($arrays[$current]) - 1 = 1
=> 0 < 1
=> $indices[$current]++
=> $indices = [1, 0, 0]
=> exit loop2
loop1:
print
=> bx1
check
$current = last element = count($arrays) = 2
loop2:
$indices[$current] == 0
count($arrays[$current]) - 1 = 0
=> 0 == 0
=> set $indices[$current] = 0
=> $indices = [1, 0, 0]
=> try next element: $current--
=> $current = 1
=> is $current == -1? no => continue
$indices[$current] == 0
count($arrays[$current]) - 1 = 1
=> 0 < 1
=> $indices[$current]++
=> $indices = [1, 1, 0]
=> exit loop2
loop1:
print
=> by1
check
$current = last element = count($arrays) = 2
loop2:
$indices[$current] == 0
count($arrays[$current]) - 1 = 0
=> 0 == 0
=> set $indices[$current] = 0
=> $indices = [1, 1, 0]
=> try next element: $current--
=> $current = 1
=> is $current == -1? no => continue
$indices[$current] == 1
count($arrays[$current]) - 1 = 1
=> 1 == 1
=> set $indices[$current] = 0
=> $indices = [1, 0, 0]
=> try next element: $current--
=> $current = 0
=> is $current == -1? no => continue
$indices[$current] == 1
count($arrays[$current]) - 1 = 1
=> 1 == 1
=> set $indices[$current] = 0
=> $indices = [0, 0, 0]
=> try next element: $current--
=> $current = -1
=> is $current == -1? yes => exit loop1
finished!