web-dev-qa-db-ja.com

PHP:array_map関数でインデックスを取得できますか?

私はPHPでマップを次のように使用しています:

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

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

関数内の値のインデックスを取得することは可能ですか?

また、インデックスが必要なコードを書いている場合、マップの代わりにforループを使用する必要がありますか?

62
Ollie Glass

確かに、 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);
168
Aron Rotteveel

無名関数を匿名配列にマッピングする場合、キーにアクセスする方法はありません。

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

複数引数のワンショット機能

「use」ボイラープレートを防ぐために、マッピングする関数を元のスコープで定義します)。

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) { /* ... */ });
8
Warbo

Dropdownクラスにパラメーターがありません。私はそれがそのような方が良いと思う:

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;
}
0
MatthieuH