PHP: Могу ли я получить индекс в функции array_map? - PullRequest
61 голосов
/ 03 мая 2011

Я использую карту в php примерно так:

function func($v) {
    return $v * 2;
}

$values = array(4, 6, 3);
$mapped = array_map(func, $values);
var_dump($mapped);

Возможно ли получить индекс значения в функции?

Также - если я пишукод, который нуждается в индексе, я должен использовать цикл for вместо карты?

Ответы [ 3 ]

164 голосов
/ 03 мая 2011

Конечно, вы можете, с помощью 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);
8 голосов
/ 21 марта 2013

При сопоставлении анонимной функции с анонимным массивом нет доступа к ключам:

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);

Функция однократного выстрела

Мы можем использовать область действия функции, чтобы предотвратить слипание существующих имен, но нам нужно добавить дополнительный слой «use»:

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,
          /* ... */));

Косвенная матрица Walk

При написании вышеупомянутого я игнорировал array_walk, так как он требует, чтобы его аргумент передавался по ссылке; однако с тех пор я понял, что это легко обойти, используя call_user_func. Я думаю, что это лучшая версия на данный момент:

call_user_func(
    'array_walk',
    array(key1 => val1,
          key2 => val2,
          /* ... */),
    function($val, $key) use ($foo) { /* ... */ });
0 голосов
/ 23 октября 2013

Вам не хватает параметра в выпадающем классе.Я думаю, что так лучше:

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;
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...