这是我非常简单的PHP 5.5兼容解决方案:
function array_map_assoc(callable $f, array $a) {
return array_column(array_map($f, array_keys($a), $a), 1, 0);
}
您提供的Callable应该本身返回一个带有两个值的数组,即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"
}
部分申请
如果您需要多次使用具有不同数组但具有相同映射功能的函数,则可以执行称为部分函数应用程序(与“ 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));
请注意,=>
而不是中,
的$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
被调用到更高阶函数中的位置,这可能就足够了。