PHP: why do these results give different results?
I have built two versions of a PHP 7 function that takes an array and returns an array list showing all the permutations of the original array elements. For example, for an input, the [1,2,3]
expected output would be all six permutations 1, 2, and 3.
I expected both versions of the function to give the same result, but can't figure out why they don't. Here is the first one (works as expected):
function permutations(array $input): array {
$func = function (array $selected, array $chooseFrom, array &$results)
use (&$func) {
foreach ($chooseFrom as $k => $unchosen):
$selectedCopy = $selected; // make a copy
$chooseFromCopy = $chooseFrom; // make a copy
$selectedCopy[] = $unchosen; // add the next unchosen item to selected list
array_splice($chooseFromCopy, $k,1); // remove the item from chooseFrom list
$func($selectedCopy, $chooseFromCopy, $results); // recursive call
endforeach;
// If we've used all items. Add selection to results
if (empty($chooseFrom)) $results[] = $selected;
};
$results = [];
$func([], $input, $results);
return $results;
}
When I call permutations([1,2])
I get the expected result: [[1,2],[2,1]]
.
Here's a broken version of the function. The only difference is foreach
:
function permutations2(array $input): array {
$func = function (array $selected, array $chooseFrom, array &$results)
use (&$func) {
foreach ($chooseFrom as $k => $unchosen):
$chooseFromCopy = $chooseFrom; // make a copy
$selected[] = $unchosen; // add the next unchosen to the selected list
array_splice($chooseFromCopy, $k, 1); // remove the item from chooseFrom list
$func($selected, $chooseFromCopy, $results); // recursive call
endforeach;
// If we've used all items. Add selection to results
if (empty($chooseFrom)) $results[] = $selected;
};
$results = [];
$func([], $input, $results);
return $results;
}
When I call permutations2([1,2])
I get a bad result:[[1,2],[1,2,1]]
Why is there a difference?
source to share
The problem is that the "$ selected" variable contains the results of the first iteration of the for loop and needs to be reinitialized before moving on to the next iteration of the loop. Storing $ selected in another variable (eg $ tempselected) before the for loop and reinitializing the $ selected variable with $ tempselected before the endforeach statement makes the code work. But these changes are almost the same as the working sample function :)
<?php
function permutations2(array $input): array {
$func = function (array $selected, array $chooseFrom, array &$results)
use (&$func) {
$selectedTemp = $selected;
foreach ($chooseFrom as $k => $unchosen):
$chooseFromCopy = $chooseFrom; // make a copy
$selected[] = $unchosen; // add the next unchosen to the selected list
array_splice($chooseFromCopy, $k, 1); // remove the item from chooseFrom list
$func($selected, $chooseFromCopy, $results); // recursive call
$selected = $selectedTemp;
endforeach;
echo("<br>After For Loop <br>");
// If we've used all items. Add selection to results
if (empty($chooseFrom)) { $results[] = $selected; }
};
$results = [];
$func([], $input, $results);
return $results;
}
$res = permutations2(['a','b','c']);
source to share