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)