PHP: Могу ли я получить индекс в функции отображения массива?
Я использую карту в php примерно так:
function func($v) {
return $v * 2;
}
$values = array(4, 6, 3);
$mapped = array_map(func, $values);
var_dump($mapped);
Можно ли получить индекс значения в функции?
Также - если я пишу код, которому нужен индекс, должен ли я использовать цикл for вместо карты?
3 answers
Конечно, вы можете, с помощью array_keys():
function func($v, $k) {
// key is now $k
return $v * 2;
}
$values = array(4, 6, 3);
$mapped = array_map(func, $values, array_keys($values));
var_dump($mapped);
При сопоставлении анонимной функции с анонимным массивом невозможно получить доступ к ключам:
array_map(
function($val) use ($foo) { /* ... */ },
array(key1 => val1,
key2 => val2,
/* ... */));
Array_reduce также не получает доступа к ключам. array_walk может получить доступ к ключам, но массив передается по ссылке, что требует уровня косвенности.
Некоторые решения таковы:
Массив пар
Это плохо, так как мы меняем исходный массив. Плюс стандартные вызовы "array()" линейно увеличиваются с длиной массив:
array_map(
function($pair) use ($foo) {
list($key, $val) = $pair;
/* ... */
},
array(array(key1, val1),
array(key2, val2),
/* ... */));
Временная переменная
Мы действуем на исходном массиве, и шаблон является постоянным, но мы можем легко изменить существующую переменную:
$i_hope_this_does_not_conflict = array(key1 => val1,
key2 => val2,
/* ... */);
array_map(
function($key, $val) use ($foo) { /* ... */ },
array_keys($i_hope_this_does_not_conflict),
$i_hope_this_does_not_conflict);
unset($i_hope_this_does_not_conflict);
Функция одного выстрела
Мы можем использовать область действия функции, чтобы предотвратить блокировку существующих имен, но должны добавить дополнительный уровень "использования":
call_user_func(
function($arr) use ($foo) {
return array_map(function($key, $val) use ($foo) { /* ... */ },
array_keys($arr),
$arr);
},
array(key1 => val1,
key2 => val2,
/* ... */));
Однократная функция с несколькими аргументами
Мы определяем функцию, которую мы сопоставляем в исходной области, чтобы предотвратить "использование" шаблон):
call_user_func(
function($f, $arr) {
return array_map($f, array_keys($arr), $arr);
},
function($key, $val) use ($foo) { /* ... */ },
array(key1 => val1,
key2 => val2,
/* ... */));
Новая функция
Интересно отметить, что наша последняя одноразовая функция имеет красивую общую подпись и очень похожа на array_map. Возможно, мы захотим дать этому имя и использовать его повторно:
function array_mapk($f, $arr) {
return array_map($f, array_keys($arr), $arr);
}
Затем наш код приложения становится:
array_mapk(
function($key, $val) use ($foo) { /* ... */ },
array(key1 => val1,
key2 => val2,
/* ... */));
Косвенный обход массива
При написании вышеизложенного я проигнорировал array_walk, так как он требует, чтобы его аргумент передавался по ссылке; однако с тех пор я понял, что с ним легко работать вокруг этого используется call_user_func. Я думаю, что это лучшая версия на данный момент:
call_user_func(
'array_walk',
array(key1 => val1,
key2 => val2,
/* ... */),
function($val, $key) use ($foo) { /* ... */ });
В раскрывающемся списке класса отсутствует параметр. Я думаю, что так будет лучше:
public function options()
{
$value = $this->value;
$mapped = array_map(function($k, $v) use ($value) {
return array(
'value' => $k,
'display' => $v,
'selected' => ($value === $k),
);
}, array_keys($this->options), $this->options);
return $mapped;
}