I\'m using a map in php like so:
function func($v) {
return $v * 2;
}
$values = array(4, 6, 3);
$mapped = array_map(func, $values);
var_dump($mapped);
For a fast and open solution (without doubling array using array_keys and similar):
/**
* Array map alternative to work with values and keys of single array.
*
* Callable receives $value and $index of $sourceArray as arguments
* If keys are not preserved via $preserveKeys - $keyCallback can be used to determinate key
*
* @param array $sourceArray
* @param callable|null $valueCallback
* @param callable|null $keyCallback
* @param bool $preserveKeys
* @return array
*/
function array_map_indexed(
array $sourceArray,
?callable $valueCallback = null,
?callable $keyCallback = null,
bool $preserveKeys = true
): array {
$newArray = [];
foreach ($sourceArray as $key => $value) {
if ($preserveKeys) {
$newArray[$keyCallback ? $keyCallback($value, $key) : $key] = $valueCallback
? $valueCallback($value, $key)
: $value;
} else {
$newArray[] = $valueCallback
? $valueCallback($value, $key)
: $value;
}
}
return $newArray;
}
Usage examples:
$result = array_map_indexed(
[
'a' => 'aValue',
'b' => 'bValue',
],
function($value, $index) {
return [$value, $index];
},
);
//Array ( [a] => Array ( [0] => aValue [1] => a ) [b] => Array ( [0] => bValue [1] => b ) )
$result = array_map_indexed(
[
'a' => 'aValue',
'b' => 'bValue',
],
function($value, $index) {
return $index.$value;
},
null,
false
);
//Array ( [0] => aaValue [1] => bbValue )
$result = array_map_indexed(
[
'a' => 'aValue',
'b' => 'bValue',
],
null,
function($value, $index) {
return $value === 'aValue' ? 'specificKey' : $index;
},
);
//Array ( [specificKey] => aValue [b] => bValue )
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)
You can create your own map function using foreach
:
<?php
function myCallback($key, $val)
{
var_dump("myCallback - key: $key, val: $val");
return $val * 2;
}
function foreachMap($callback, $givenArray) {
$result = [];
foreach ($givenArray as $key=>$val) {
$result[$key] = $callback($key, $val);
}
return $result;
}
$values = array(4, 6, 3);
$mapped = foreachMap('myCallback', $values);
var_dump($mapped);
try: https://3v4l.org/pmFlB
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:
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),
/* ... */));
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);
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,
/* ... */));
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,
/* ... */));
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,
/* ... */));
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) { /* ... */ });