PHP 的 array_map 包括键
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/13036160/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
PHP's array_map including keys
提问by José Tomás Tocino
Is there a way of doing something like this:
有没有办法做这样的事情:
$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)));
But instead of calling array_keysand array_values, directly passing the $test_arrayvariable?
但是不是调用array_keysand array_values,而是直接传递$test_array变量?
The desired output is:
所需的输出是:
array(2) {
[0]=>
string(27) "first_key loves first_value"
[1]=>
string(29) "second_key loves second_value"
}
采纳答案by eis
Not with array_map, as it doesn't handle keys.
不适用于 array_map,因为它不处理键。
array_walkdoes:
$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"
// }
It does change the array given as parameter however, so it's not exactly functional programming (as you have the question tagged like that). Also, as pointed out in the comment, this will only change the values of the array, so the keys won't be what you specified in the question.
然而,它确实改变了作为参数给出的数组,所以它不完全是函数式编程(因为你有这样标记的问题)。此外,正如评论中指出的那样,这只会更改数组的值,因此键不会是您在问题中指定的键。
You could write a function that fixes the points above yourself if you wanted to, like this:
如果您愿意,您可以编写一个函数来修复上面的问题,如下所示:
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"
// }
回答by Kevin Beal
This is probably the shortest and easiest to reason about:
这可能是最短和最容易推理的:
$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')
)
回答by Nicholas Shanks
Here's my very simple, PHP 5.5-compatible solution:
这是我的非常简单的 PHP 5.5 兼容解决方案:
function array_map_assoc(callable $f, array $a) {
return array_column(array_map($f, array_keys($a), $a), 1, 0);
}
The callable you supply should itself return an array with two values, i.e. return [key, value]. The inner call to array_maptherefore produces an array of arrays. This then gets converted back to a single-dimension array by array_column.
您提供的可调用对象本身应该返回一个包含两个值的数组,即return [key, value]. 因此,内部调用会array_map生成一个数组数组。然后通过 将其转换回单维数组array_column。
Usage
用法
$ordinals = [
'first' => '1st',
'second' => '2nd',
'third' => '3rd',
];
$func = function ($k, $v) {
return ['new ' . $k, 'new ' . $v];
};
var_dump(array_map_assoc($func, $ordinals));
Output
输出
array(3) {
["new first"]=>
string(7) "new 1st"
["new second"]=>
string(7) "new 2nd"
["new third"]=>
string(7) "new 3rd"
}
Partial application
部分应用
In case you need to use the function many times with different arrays but the same mapping function, you can do something called partial function application(related to ‘currying'), which allows you to only pass in the data array upon invocation:
如果您需要对不同的数组但相同的映射函数多次使用该函数,您可以执行称为部分函数应用程序的操作(与 ' 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));
Which produces the same output, given $funcand $ordinalsare as earlier.
产生相同的输出,给定$func和$ordinals如前所述。
NOTE: if your mapped function returns the same keyfor two different inputs, the value associated with the later key will win.Reverse the input array and output result of array_map_assocto allow earlier keys to win. (The returned keys in my example cannot collide as they incorporate the key of the source array, which in turn must be unique.)
注意:如果您的映射函数为两个不同的输入返回相同的键,则与后一个键关联的值将获胜。反转 的输入数组和输出结果array_map_assoc以允许较早的键获胜。(我的示例中返回的键不能冲突,因为它们包含源数组的键,而源数组又必须是唯一的。)
Alternative
选择
Following is a variant of the above, which might prove more logical to some, but requires PHP 5.6:
以下是上述的变体,对某些人来说可能更合乎逻辑,但需要 PHP 5.6:
function array_map_assoc(callable $f, array $a) {
return array_merge(...array_map($f, array_keys($a), $a));
}
In this variant, your supplied function (over which the data array is mapped) should instead return an associative array with one row, i.e. return [key => value].
The result of mapping the callable is then simply unpacked and passed to array_merge. As earlier, returning a duplicate key will result in later values winning.
在此变体中,您提供的函数(数据数组映射到该函数上)应该返回一个包含一行的关联数组,即return [key => value]. 然后将可调用对象的映射结果简单地解包并传递给array_merge. 如前所述,返回重复键将导致后面的值获胜。
n.b. Alex83690 has noted in a comment that using
array_replacehere in the stead ofarray_mergewould preserve integer keys.array_replacedoes not modify the input array, so is safe for functional code.
nb Alex83690 在评论中指出,在
array_replace此处使用代替array_merge将保留整数键。array_replace不修改输入数组,因此对于功能代码是安全的。
If you are on PHP 5.3 to 5.5, the following is equivalent. It uses array_reduceand the binary +array operator to convert the resulting two-dimensional array down to a one-dimensional array whilst preserving keys:
如果您使用的是 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;
}, []);
}
Usage
用法
Both of these variants would be used thus:
因此,将使用这两种变体:
$ordinals = [
'first' => '1st',
'second' => '2nd',
'third' => '3rd',
];
$func = function ($k, $v) {
return ['new ' . $k => 'new ' . $v];
};
var_dump(array_map_assoc($func, $ordinals));
Note the =>instead of ,in $func.
注意=>代替,in $func。
The output is the same as before, and each can be partially applied in the same way as before.
输出与以前相同,并且每个都可以以与以前相同的方式部分应用。
?Summary
?概括
The goal of the original question is to make the invocation of the call as simple as possible, at the expense of having a more complicated function that gets invoked; especially, to have the ability to pass the data array in as a single argument, without splitting the keys and values. Using the function supplied at the start of this answer:
原始问题的目标是使调用的调用尽可能简单,代价是调用更复杂的函数;特别是,能够将数据数组作为单个参数传入,而无需拆分键和值。使用本答案开头提供的函数:
$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)));
Or, for this question only, we can make a simplification to array_map_assoc()function that drops output keys, since the question does not ask for them:
或者,仅针对这个问题,我们可以简化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));
So the answer is NO, you can't avoid calling array_keys, but you can abstract out the place where array_keysgets called into a higher-order function, which might be good enough.
所以答案是否定的,你不能避免调用array_keys,但你可以抽象出array_keys被调用的地方到一个高阶函数中,这可能已经足够了。
回答by Tadas Sasnauskas
With PHP5.3 or later:
使用 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)
)
);
回答by Jijo
This is how I've implemented this in my project.
这就是我在我的项目中实现它的方式。
function array_map_associative(callable $callback, $array) {
/* map original array keys, and call $callable with $key and value of $key from original array. */
return array_map(function($key) use ($callback, $array){
return $callback($key, $array[$key]);
}, array_keys($array));
}
回答by IanS
Look here! There is a trivial solution!
看这里!有一个简单的解决方案!
function array_map2(callable $f, array $a)
{
return array_map($f, array_keys($a), $a);
}
As stated in the question, array_mapalready has exactly the functionality required. The other answers here seriously overcomplicate things: array_walkis not functional.
正如问题中所述,array_map已经完全具备所需的功能。这里的其他答案严重使事情过于复杂:array_walk不起作用。
Usage
用法
Exactly as you would expect from your example:
正如您对示例所期望的那样:
$test_array = array("first_key" => "first_value",
"second_key" => "second_value");
var_dump(array_map2(function($a, $b) { return "$a loves $b"; }, $test_array));
回答by ryanve
By "manual loop" I meant write a custom function that uses foreach. This returns a new array like array_mapdoes because the function's scope causes $arrayto be a copy—not a reference:
“手动循环”是指编写一个使用foreach. 这将返回一个新数组array_map,因为函数的作用域$array是一个副本,而不是一个引用:
function map($array, callable $fn) {
foreach ($array as $k => &$v) $v = call_user_func($fn, $k, $v);
return $array;
}
Your technique using array_mapwith array_keysthough actually seems simpler and is more powerful because you can use nullas a callback to return the key-value pairs:
虽然实际上使用array_mapwith 的技术array_keys看起来更简单并且更强大,因为您可以将其null用作回调来返回键值对:
function map($array, callable $fn = null) {
return array_map($fn, array_keys($array), $array);
}
回答by José Tomás Tocino
Based on eis's answer, here's what I eventually did in order to avoid messing the original array:
根据eis 的回答,这是我最终为了避免弄乱原始数组所做的:
$test_array = array("first_key" => "first_value",
"second_key" => "second_value");
$result_array = array();
array_walk($test_array,
function($a, $b) use (&$result_array)
{ $result_array[] = "$b loves $a"; },
$result_array);
var_dump($result_array);
回答by Julio Vedovatto
I made this function, based on eis's answer:
我根据eis的回答做了这个功能:
function array_map_($callback, $arr) {
if (!is_callable($callback))
return $arr;
$result = array_walk($arr, function(&$value, $key) use ($callback) {
$value = call_user_func($callback, $key, $value);
});
if (!$result)
return false;
return $arr;
}
Example:
例子:
$test_array = array("first_key" => "first_value",
"second_key" => "second_value");
var_dump(array_map_(function($key, $value){
return $key . " loves " . $value;
}, $arr));
Output:
输出:
array (
'first_key' => 'first_key loves first_value,
'second_key' => 'second_key loves second_value',
)
Off course, you can use array_valuesto return exactly what OP wants.
当然,您可以使用array_values来准确返回 OP 想要的内容。
array_values(array_map_(function($key, $value){
return $key . " loves " . $value;
}, $test_array))
回答by Athari
YaLinqolibrary* is well suited for this sort of task. It's a port of LINQ from .NET which fully supports values and keys in all callbacks and resembles SQL. For example:
YaLinqo库* 非常适合此类任务。它是 .NET 的 LINQ 端口,它完全支持所有回调中的值和键,并且类似于 SQL。例如:
$mapped_array = from($test_array)
->select(function ($v, $k) { return "$k loves $v"; })
->toArray();
or just:
要不就:
$mapped_iterator = from($test_array)->select('"$k loves $v"');
Here, '"$k loves $v"'is a shortcut for full closure syntax which this library supports. toArray()in the end is optional. The method chain returns an iterator, so if the result just needs to be iterated over using foreach, toArraycall can be removed.
这'"$k loves $v"'是该库支持的完整闭包语法的快捷方式。toArray()最后是可选的。方法链返回一个迭代器,所以如果结果只需要在 using 上迭代foreach,toArray就可以删除调用。
* developed by me
* 由我开发

