Jos*_*ino 179 php functional-programming
有没有办法做这样的事情:
$test_array = array("first_key" => "first_value",
"second_key" => "second_value");
var_dump(array_map(function($a, $b) { return "$a loves $b"; },
array_keys($test_array),
array_values($test_array)));
Run Code Online (Sandbox Code Playgroud)
但是,而不是调用,array_keys
并array_values
直接传递$test_array
变量?
所需的输出是:
array(2) {
[0]=>
string(27) "first_key loves first_value"
[1]=>
string(29) "second_key loves second_value"
}
Run Code Online (Sandbox Code Playgroud)
eis*_*eis 179
不使用array_map,因为它不处理键.
$test_array = array("first_key" => "first_value",
"second_key" => "second_value");
array_walk($test_array, function(&$a, $b) { $a = "$b loves $a"; });
var_dump($test_array);
// array(2) {
// ["first_key"]=>
// string(27) "first_key loves first_value"
// ["second_key"]=>
// string(29) "second_key loves second_value"
// }
Run Code Online (Sandbox Code Playgroud)
它确实改变了作为参数给出的数组,因此它不完全是函数式编程(因为你有像这样标记的问题).此外,正如注释中所指出的,这只会更改数组的值,因此键不会是您在问题中指定的键.
如果你愿意,你可以编写一个修复上面各点的函数,如下所示:
function mymapper($arrayparam, $valuecallback) {
$resultarr = array();
foreach ($arrayparam as $key => $value) {
$resultarr[] = $valuecallback($key, $value);
}
return $resultarr;
}
$test_array = array("first_key" => "first_value",
"second_key" => "second_value");
$new_array = mymapper($test_array, function($a, $b) { return "$a loves $b"; });
var_dump($new_array);
// array(2) {
// [0]=>
// string(27) "first_key loves first_value"
// [1]=>
// string(29) "second_key loves second_value"
// }
Run Code Online (Sandbox Code Playgroud)
Kev*_*eal 125
这可能是最短且最容易推理的:
$states = array('az' => 'Arizona', 'al' => 'Alabama');
array_map(function ($short, $long) {
return array(
'short' => $short,
'long' => $long
);
}, array_keys($states), $states);
// produces:
array(
array('short' => 'az', 'long' => 'Arizona'),
array('short' => 'al', 'long' => 'Alabama')
)
Run Code Online (Sandbox Code Playgroud)
Nic*_*nks 58
这是我非常简单的PHP 5.5兼容解决方案:
function array_map_assoc(callable $f, array $a) {
return array_column(array_map($f, array_keys($a), $a), 1, 0);
}
Run Code Online (Sandbox Code Playgroud)
你提供的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));
Run Code Online (Sandbox Code Playgroud)
array(3) {
["new first"]=>
string(7) "new 1st"
["new second"]=>
string(7) "new 2nd"
["new third"]=>
string(7) "new 3rd"
}
Run Code Online (Sandbox Code Playgroud)
如果您需要使用不同数组但相同映射函数多次使用该函数,您可以执行一些称为部分函数应用程序(与' 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));
Run Code Online (Sandbox Code Playgroud)
它产生相同的输出,给定$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));
}
Run Code Online (Sandbox Code Playgroud)
在此变体中,您提供的函数(数据数据映射在其上)应该返回一行关联数组,即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;
}, []);
}
Run Code Online (Sandbox Code Playgroud)
因此可以使用这两种变体:
$ordinals = [
'first' => '1st',
'second' => '2nd',
'third' => '3rd',
];
$func = function ($k, $v) {
return ['new ' . $k => 'new ' . $v];
};
var_dump(array_map_assoc($func, $ordinals));
Run Code Online (Sandbox Code Playgroud)
注意=>
而不是,
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)));
Run Code Online (Sandbox Code Playgroud)
或者,仅针对此问题,我们可以简化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));
Run Code Online (Sandbox Code Playgroud)
所以答案是否定的,你无法避免调用array_keys
,但你可以抽象出array_keys
被调用到更高阶函数的地方,这可能已经足够了.
Tad*_*kas 20
使用PHP5.3或更高版本:
$test_array = array("first_key" => "first_value",
"second_key" => "second_value");
var_dump(
array_map(
function($key) use ($test_array) { return "$key loves ${test_array[$key]}"; },
array_keys($test_array)
)
);
Run Code Online (Sandbox Code Playgroud)
Ost*_*PHP 14
$array = [
'category1' => 'first category',
'category2' => 'second category',
];
$new = array_map(function($key, $value) {
return "{$key} => {$value}";
}, array_keys($array), $array);
Run Code Online (Sandbox Code Playgroud)
看这里!有一个简单的解决方案!
function array_map2(callable $f, array $a)
{
return array_map($f, array_keys($a), $a);
}
Run Code Online (Sandbox Code Playgroud)
正如问题中所述,array_map
已经完全具备所需的功能。这里的其他答案严重使事情过于复杂:array_walk
不起作用。
用法
正如您对示例所期望的那样:
$test_array = array("first_key" => "first_value",
"second_key" => "second_value");
var_dump(array_map2(function($a, $b) { return "$a loves $b"; }, $test_array));
Run Code Online (Sandbox Code Playgroud)
我将使用 5.6 或更高版本为该问题添加另一个解决方案。不知道它是否比已经很好的解决方案更有效(可能不是),但对我来说它更容易阅读:
$myArray = [
"key0" => 0,
"key1" => 1,
"key2" => 2
];
array_combine(
array_keys($myArray),
array_map(
function ($intVal) {
return strval($intVal);
},
$myArray
)
);
Run Code Online (Sandbox Code Playgroud)
在 中strval()
用作示例函数array_map
,这将生成:
array(3) {
["key0"]=>
string(1) "0"
["key1"]=>
string(1) "1"
["key2"]=>
string(1) "2"
}
Run Code Online (Sandbox Code Playgroud)
希望我不是唯一一个觉得这很容易掌握的人。
从一个键数组和一个值数组array_combine
创建一个key => value
数组,其余的都是不言自明的。