这是我非常简单、兼容 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"
}
部分应用
如果你需要多次使用不同数组但映射函数相同的函数,你可以做一个叫做partial function application(与'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。如前所述,返回重复键将导致后面的值获胜。
n.b. 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));
注意=> 中的,,而不是$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));
所以答案是NO,你不能避免调用array_keys,但是你可以把array_keys被调用的地方抽象出来放到一个高阶函数中,这样可能会很好够了。