PHP: Can I get the index in an array_map function? PHP: Can I get the index in an array_map function? arrays arrays

PHP: Can I get the index in an array_map function?


Sure you can, with the help of 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);


When mapping an anonymous function over an anonymous array, there is no way to access the keys:

array_map(    function($val) use ($foo) { /* ... */ },    array(key1 => val1,          key2 => val2,          /* ... */));

array_reduce doesn't get access to the keys either. array_walk can access keys, but the array is passed by reference, which requires a layer of indirection.

Some solutions are:

Array of pairs

This is bad, since we're changing the original array. Plus the boilerplate "array()" calls increase linearly with the length of the array:

array_map(    function($pair) use ($foo) {        list($key, $val) = $pair;        /* ... */    },    array(array(key1, val1),          array(key2, val2),          /* ... */));

Temporary variable

We're acting on the original array, and the boilerplate is constant, but we can easily clobber an existing variable:

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

One-shot function

We can use function scope to prevent clobbering existing names, but have to add an extra layer of "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,          /* ... */));

Multi-argument one-shot function

We define the function we're mapping in the original scope to prevent the "use" boilerplate):

call_user_func(    function($f, $arr) {        return array_map($f, array_keys($arr), $arr);    },    function($key, $val) use ($foo) { /* ... */ },    array(key1 => val1,          key2 => val2,          /* ... */));

New function

The interesting thing to note is that our last one-shot function has a nice, generic signature and looks a lot like array_map. We might want to give this a name and re-use it:

function array_mapk($f, $arr) {    return array_map($f, array_keys($arr), $arr);}

Our application code then becomes:

array_mapk(    function($key, $val) use ($foo) { /* ... */ },    array(key1 => val1,          key2 => val2,          /* ... */));

Indirect Array Walk

When writing the above I'd ignored array_walk since it requires its argument to be passed by reference; however, I've since realised that it's easy to work around this using call_user_func. I think this is the best version so far:

call_user_func(    'array_walk',    array(key1 => val1,          key2 => val2,          /* ... */),    function($val, $key) use ($foo) { /* ... */ });


Very simple:

Only array_map fuction: does not have index key!

 $params = [4,6,2,11,20]; $data = array_map(function($v) { return ":id{$v}";}, $params); array (size=5)  0 => string ':id4' (length=4)  1 => string ':id6' (length=4)  2 => string ':id2' (length=4)  3 => string ':id11' (length=5)  4 => string ':id20' (length=5)

Now, combine with array_keys:

$data = array_map(    function($k) use ($params) { return ":id{$k}_${params[$k]}"; },    array_keys($params) );array (size=5)  0 => string ':id0_4' (length=6)  1 => string ':id1_6' (length=6)  2 => string ':id2_2' (length=6)  3 => string ':id3_11' (length=7)  4 => string ':id4_20' (length=7)