У меня есть алгоритм, чтобы найти все уникальные комбинации множества foods
. Если какая-либо из комбинаций соответствует нашему calories value
тогда она должна возвращать значение true.
Вот мой подход:
<?php
$food = [
['a', 70],
['b', 5],
['c', 20],
['d', 10]
];
function eat($calories, $food, $k = 0, $p = []) {
for ($i=$k; $i < count($food); $i++) {
$r = array_merge($p, [$i]);
$c = 0;
foreach ($r as $j) {
$c += $food[$j][1];
}
if ($c == $calories) {
echo "success";
return true;
}
eat($calories, $food, $i+1, $r);
}
}
var_dump(eat(100, $food));
?>
Возникает вопрос: почему этот код выводит "успех", но не возвращает true?
Вот онлайн-исполнение:
Исходная функция, которую вы вызываете, никогда не возвращает true, последующее funtion, которое вызывается, возвращает true для своего "родителя", но это истинное значение никогда не возвращается исходному вызывающему. Исправление будет следующим:
if (eat($calories, $food, $i+1, $r)) {
return true;
}
Это проверяет, что возвращает рекурсивная функция, и если ее значение true
, возвращается true
Вы вызываете функцию рекурсивно. Сбрасываемое значение будет возвращенным значением первого вызова, поскольку вы игнорируете возвращаемые значения других вызовов.
Здесь вам кажется, что вам нужно только выполнить один успешный вызов, после чего функция должна быть прервана. Таким образом, вы можете проверить успех, и если это произошло, верните true, чтобы предотвратить дальнейшую работу функции, и сообщите вызывающему абоненту (это может быть первый вызов или любые другие вызовы в рекурсии), что вызов был успешным.
<?php
$food = [
['a', 70],
['b', 5],
['c', 20],
['d', 10]
];
function eat($calories, $food, $k = 0, $p = []) {
for ($i=$k; $i < count($food); $i++) {
$r = array_merge($p, [$i]);
$c = 0;
foreach ($r as $j) {
$c += $food[$j][1];
}
if ($c == $calories) {
echo "success";
return true;
}
if(eat($calories, $food, $i+1, $r))
return true;
}
}
var_dump(eat(100, $food));
?>
Немного другой подход к рекурсивной функции массива будет заключаться в использовании встроенного функции arrayIterator.
$food = array(
'a'=> 70,
'b'=> 5,
'c'=> 20,
'd'=> 10,
'e'=> 99
);
function eat( $calories, $food, $p=array() ){
$a = new ArrayObject( array_merge( $food, $p ) );
$iterator = $a->getIterator();
while( $iterator->valid() ) {
if( $iterator->current()==$calories ) {
echo 'success: key='.$iterator->key().' value='.$iterator->current();
return true;
}
$iterator->next();
}
return false;
}
eat( 120, $food, array( 'banana'=>500,'apple'=>120 ) );
$success = eat(…);
результат рекурсии. Либо верните преждевременно, когда истина, либо оставьте его до окончания цикла, а затемreturn
его.