这是我非常简单的、与 PHP 5.5 兼容的解决方案:
function array_map_assoc(callable $f, array $a) {
return array_column(array_map($f, array_keys($a), $a), 1, 0);
}
您提供的可调用对象本身应该返回一个包含两个值的数组,即return [key, value]
. 因此,内部调用会array_map
产生一个数组数组。然后通过 将其转换回一维数组array_column
。
用法
$ordinals = [
'first' => '1st',
'second' => '2nd',
'third' => '3rd',
];
$func = function ($k, $v) {
return ['new ' . $k, 'new ' . $v];
};
var_dump(array_map_assoc($func, $ordinals));
输出
array(3) {
["new first"]=>
string(7) "new 1st"
["new second"]=>
string(7) "new 2nd"
["new third"]=>
string(7) "new 3rd"
}
部分应用
如果你需要多次使用不同数组但映射函数相同的函数,你可以做一些叫做偏函数应用的事情(与 '<a href="https://en.wikipedia.org/wiki/Currying" rel="noreferrer">currying'),它允许您仅在调用时传入数据数组:
function array_map_assoc_partial(callable $f) {
return function (array $a) use ($f) {
return array_column(array_map($f, array_keys($a), $a), 1, 0);
};
}
...
$my_mapping = array_map_assoc_partial($func);
var_dump($my_mapping($ordinals));
它产生相同的输出,给定$func
并且$ordinals
如前所述。
注意:如果您的映射函数为两个不同的输入返回相同的键,则与后一个键关联的值将获胜。反转输入数组和输出结果array_map_assoc
以允许较早的键获胜。(在我的示例中,返回的键不能冲突,因为它们包含源数组的键,而源数组的键又必须是唯一的。)
选择
以下是上述的变体,对某些人来说可能更合乎逻辑,但需要 PHP 5.6:
function array_map_assoc(callable $f, array $a) {
return array_merge(...array_map($f, array_keys($a), $a));
}
在此变体中,您提供的函数(在其上映射数据数组)应改为返回一个具有一行的关联数组,即return [key => value]
. 然后将可调用的映射结果简单地解包并传递给array_merge
. 如前所述,返回重复键将导致后面的值获胜。
nb Alex83690 在评论中指出,使用array_replace
此处代替array_merge
将保留整数键。array_replace
不修改输入数组,因此对于功能代码是安全的。
如果您使用的是 PHP 5.3 到 5.5,则以下内容是等效的。它使用array_reduce
和二元+
数组运算符将生成的二维数组转换为一维数组,同时保留键:
function array_map_assoc(callable $f, array $a) {
return array_reduce(array_map($f, array_keys($a), $a), function (array $acc, array $a) {
return $acc + $a;
}, []);
}
用法
因此将使用这两种变体:
$ordinals = [
'first' => '1st',
'second' => '2nd',
'third' => '3rd',
];
$func = function ($k, $v) {
return ['new ' . $k => 'new ' . $v];
};
var_dump(array_map_assoc($func, $ordinals));
注意=>
代替,
in $func
。
输出和以前一样,每个都可以像以前一样部分应用。
概括
原始问题的目标是使调用的调用尽可能简单,代价是调用更复杂的函数;特别是,能够将数据数组作为单个参数传入,而无需拆分键和值。使用此答案开头提供的函数:
$test_array = ["first_key" => "first_value",
"second_key" => "second_value"];
$array_map_assoc = function (callable $f, array $a) {
return array_column(array_map($f, array_keys($a), $a), 1, 0);
};
$f = function ($key, $value) {
return [$key, $key . ' loves ' . $value];
};
var_dump(array_values($array_map_assoc($f, $test_array)));
或者,仅针对这个问题,我们可以简化array_map_assoc()
删除输出键的功能,因为问题不要求它们:
$test_array = ["first_key" => "first_value",
"second_key" => "second_value"];
$array_map_assoc = function (callable $f, array $a) {
return array_map($f, array_keys($a), $a);
};
$f = function ($key, $value) {
return $key . ' loves ' . $value;
};
var_dump($array_map_assoc($f, $test_array));
所以答案是否定的,你不能避免调用array_keys
,但是你可以把被调用的地方抽象array_keys
成一个高阶函数,这可能已经足够好了。