php array_map、array_walk 和 array_filter 的区别
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/3432257/
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
Difference between array_map, array_walk and array_filter
提问by Artefacto
What exactly is the the difference between array_map
, array_walk
and array_filter
. What I could see from documentation is that you could pass a callback function to perform an action on the supplied array. But I don't seem to find any particular difference between them.
array_map
,array_walk
和之间究竟有什么区别array_filter
。我从文档中看到的是,您可以传递一个回调函数来对提供的数组执行操作。但我似乎没有发现它们之间有什么特别的区别。
Do they perform the same thing?
Can they be used interchangeably?
他们做同样的事情吗?
它们可以互换使用吗?
I would appreciate your help with illustrative example if they are different at all.
如果它们完全不同,我将不胜感激您对说明性示例的帮助。
回答by Artefacto
- Changing Values:
array_map
cannot change the values inside input array(s) whilearray_walk
can; in particular,array_map
never changes its arguments.
- Array Keys Access:
array_map
cannot operate with the array keys,array_walk
can.
- Return Value:
array_map
returns a new array,array_walk
only returnstrue
. Hence, if you don't want to create an array as a result of traversing one array, you should usearray_walk
.
- Iterating Multiple Arrays:
array_map
also can receive an arbitrary number of arrays and it can iterate over them in parallel, whilearray_walk
operates only on one.
- Passing Arbitrary Data to Callback:
array_walk
can receive an extra arbitrary parameter to pass to the callback. This mostly irrelevant since PHP 5.3 (when anonymous functionswere introduced).
- Length of Returned Array:
- The resulting array of
array_map
has the same length as that of the largest input array;array_walk
does not return an array but at the same time it cannot alter the number of elements of original array;array_filter
picks only a subset of the elements of the array according to a filtering function. It does preserve the keys.
- The resulting array of
- 更改值:
array_map
不能更改输入数组中的值,而array_walk
可以;特别是,array_map
永远不会改变它的论点。
- 数组键访问:
array_map
不能用数组键操作,array_walk
可以。
- 返回值:
array_map
返回一个新数组,array_walk
只返回true
. 因此,如果您不想因为遍历一个数组而创建一个数组,则应该使用array_walk
.
- 迭代多个数组:
array_map
也可以接收任意数量的数组,并且可以并行迭代它们,而array_walk
只对一个数组进行操作。
- 将任意数据传递给回调:
array_walk
可以接收一个额外的任意参数传递给回调。自 PHP 5.3(引入匿名函数时)以来,这几乎无关紧要。
- 返回数组的长度:
- 结果数组的
array_map
长度与最大输入数组的长度相同;array_walk
不返回数组但同时不能改变原始数组的元素数;array_filter
根据过滤函数只选择数组元素的一个子集。它确实保留了密钥。
- 结果数组的
Example:
例子:
<pre>
<?php
$origarray1 = array(2.4, 2.6, 3.5);
$origarray2 = array(2.4, 2.6, 3.5);
print_r(array_map('floor', $origarray1)); // $origarray1 stays the same
// changes $origarray2
array_walk($origarray2, function (&$v, $k) { $v = floor($v); });
print_r($origarray2);
// this is a more proper use of array_walk
array_walk($origarray1, function ($v, $k) { echo "$k => $v", "\n"; });
// array_map accepts several arrays
print_r(
array_map(function ($a, $b) { return $a * $b; }, $origarray1, $origarray2)
);
// select only elements that are > 2.5
print_r(
array_filter($origarray1, function ($a) { return $a > 2.5; })
);
?>
</pre>
Result:
结果:
Array
(
[0] => 2
[1] => 2
[2] => 3
)
Array
(
[0] => 2
[1] => 2
[2] => 3
)
0 => 2.4
1 => 2.6
2 => 3.5
Array
(
[0] => 4.8
[1] => 5.2
[2] => 10.5
)
Array
(
[1] => 2.6
[2] => 3.5
)
回答by Kendall Hopkins
The idea of mappingan function to array of data comes from functional programming. You shouldn't think about array_map
as a foreach
loop that calls a function on each element of the array (even though that's how it's implemented). It should be thought of as applying the function to each element in the array independently.
将函数映射到数据数组的想法来自函数式编程。您不应将其array_map
视为foreach
对数组的每个元素调用函数的循环(即使它是这样实现的)。它应该被认为是将函数独立地应用于数组中的每个元素。
In theory such things as function mapping can be done in parallel since the function being applied to the data should ONLY affect the data and NOT the global state. This is because an array_map
could choose any order in which to apply the function to the items in (even though in PHP it doesn't).
理论上,函数映射之类的事情可以并行完成,因为应用于数据的函数应该只影响数据而不是全局状态。这是因为array_map
可以选择将函数应用于其中的项目的任何顺序(即使在 PHP 中它没有)。
array_walk
on the other hand it the exact opposite approach to handling arrays of data. Instead of handling each item separately, it uses a state (&$userdata
) and can edit the item in place (much like a foreach loop). Since each time an item has the $funcname
applied to it, it could change the global state of the program and therefor requires a single correctway of processing the items.
array_walk
另一方面,它是处理数据数组的完全相反的方法。它不是单独处理每个项目,而是使用状态 ( &$userdata
) 并且可以就地编辑项目(很像 foreach 循环)。由于每次应用一个项目$funcname
时,它都可能改变程序的全局状态,因此需要一种处理项目的正确方法。
Back in PHP land, array_map
and array_walk
are almost identical except array_walk
gives you more control over the iteration of data and is normally used to "change" the data in-place vs returning a new "changed" array.
回到 PHP 领域,除了让您更好地控制数据迭代之外array_map
,array_walk
它们几乎相同array_walk
,并且通常用于就地“更改”数据与返回新的“更改”数组。
array_filter
is really an application of array_walk
(or array_reduce
) and it more-or-less just provided for convenience.
array_filter
实际上是array_walk
(or array_reduce
) 的一个应用程序,它或多或少只是为了方便而提供的。
回答by Steven Schlansker
From the documentation,
从文档中,
bool array_walk ( array &$array , callback $funcname [, mixed $userdata ] ) <-return bool
bool array_walk ( array &$array , callback $funcname [, mixed $userdata ] ) <-return bool
array_walktakes an array and a function F
and modifies it by replacing every element x with F(x)
.
array_walk接受一个数组和一个函数F
,并通过将每个元素 x 替换为 来修改它F(x)
。
array array_map ( callback $callback , array $arr1 [, array $... ] )<-return array
array array_map ( callback $callback , array $arr1 [, array $... ] )<-return array
array_mapdoes the exact same thing exceptthat instead of modifying in-place it will return a new array with the transformed elements.
array_map做完全相同的事情,只是它不会就地修改,而是返回一个带有转换元素的新数组。
array array_filter ( array $input [, callback $callback ] )<-return array
array array_filter ( array $input [, callback $callback ] )<-return array
array_filterwith function F
, instead of transforming the elements, will remove any elements for which F(x)
is not true
array_filter与 function F
,而不是转换元素,将删除任何F(x)
不为真的元素
回答by Warbo
The other answers demonstrate the difference between array_walk (in-place modification) and array_map (return modified copy) quite well. However, they don't really mention array_reduce, which is an illuminating way to understand array_map and array_filter.
其他答案很好地展示了 array_walk(就地修改)和 array_map(返回修改后的副本)之间的区别。然而,他们并没有真正提到array_reduce,这是理解array_map 和array_filter 的一种启发性方式。
The array_reduce function takes an array, a two-argument function and an 'accumulator', like this:
array_reduce 函数接受一个数组、一个双参数函数和一个“累加器”,如下所示:
array_reduce(array('a', 'b', 'c', 'd'),
'my_function',
$accumulator)
The array's elements are combined with the accumulator one at a time, using the given function. The result of the above call is the same as doing this:
使用给定的函数,数组的元素一次一个地与累加器组合。上述调用的结果与执行此操作的结果相同:
my_function(
my_function(
my_function(
my_function(
$accumulator,
'a'),
'b'),
'c'),
'd')
If you prefer to think in terms of loops, it's like doing the following (I've actually used this as a fallback when array_reduce wasn't available):
如果您更喜欢从循环的角度思考,就像执行以下操作(当 array_reduce 不可用时,我实际上将其用作后备):
function array_reduce($array, $function, $accumulator) {
foreach ($array as $element) {
$accumulator = $function($accumulator, $element);
}
return $accumulator;
}
This looping version makes it clear why I've called the third argument an 'accumulator': we can use it to accumulate results through each iteration.
这个循环版本清楚地说明了为什么我将第三个参数称为“累加器”:我们可以使用它来累积每次迭代的结果。
So what does this have to do with array_map and array_filter? It turns out that they're both a particular kind of array_reduce. We can implement them like this:
那么这与array_map 和array_filter 有什么关系呢?事实证明,它们都是一种特殊的array_reduce。我们可以像这样实现它们:
array_map($function, $array) === array_reduce($array, $MAP, array())
array_filter($array, $function) === array_reduce($array, $FILTER, array())
Ignore the fact that array_map and array_filter take their arguments in a different order; that's just another quirk of PHP. The important point is that the right-hand-side is identical except for the functions I've called $MAP and $FILTER. So, what do they look like?
忽略 array_map 和 array_filter 以不同顺序获取参数的事实;这只是 PHP 的另一个怪癖。重要的一点是,除了我称为 $MAP 和 $FILTER 的函数之外,右侧是相同的。那么,它们长什么样子呢?
$MAP = function($accumulator, $element) {
$accumulator[] = $function($element);
return $accumulator;
};
$FILTER = function($accumulator, $element) {
if ($function($element)) $accumulator[] = $element;
return $accumulator;
};
As you can see, both functions take in the $accumulator and return it again. There are two differences in these functions:
如您所见,这两个函数都接收 $accumulator 并再次返回它。这些函数有两个区别:
- $MAP will always append to $accumulator, but $FILTER will only do so if $function($element) is TRUE.
- $FILTER appends the original element, but $MAP appends $function($element).
- $MAP 将始终附加到 $accumulator,但 $FILTER 仅在 $function($element) 为 TRUE 时才会这样做。
- $FILTER 附加原始元素,但 $MAP 附加 $function($element)。
Note that this is far from useless trivia; we can use it to make our algorithms more efficient!
请注意,这远非无用的琐事;我们可以用它来提高我们的算法效率!
We can often see code like these two examples:
我们经常可以看到类似下面两个例子的代码:
// Transform the valid inputs
array_map('transform', array_filter($inputs, 'valid'))
// Get all numeric IDs
array_filter(array_map('get_id', $inputs), 'is_numeric')
Using array_map and array_filter instead of loops makes these examples look quite nice. However, it can be very inefficient if $inputs is large, since the first call (map or filter) will traverse $inputs and build an intermediate array. This intermediate array is passed straight into the second call, which will traverse the whole thing again, then the intermediate array will need to be garbage collected.
使用 array_map 和 array_filter 代替循环使这些示例看起来很不错。然而,如果 $inputs 很大,它可能会非常低效,因为第一次调用(map 或 filter)将遍历 $inputs 并构建一个中间数组。这个中间数组直接传递给第二次调用,它会再次遍历整个事物,然后中间数组需要被垃圾回收。
We can get rid of this intermediate array by exploiting the fact that array_map and array_filter are both examples of array_reduce. By combining them, we only have to traverse $inputs once in each example:
我们可以通过利用 array_map 和 array_filter 都是 array_reduce 的例子来摆脱这个中间数组。通过组合它们,我们只需在每个示例中遍历 $inputs 一次:
// Transform valid inputs
array_reduce($inputs,
function($accumulator, $element) {
if (valid($element)) $accumulator[] = transform($element);
return $accumulator;
},
array())
// Get all numeric IDs
array_reduce($inputs,
function($accumulator, $element) {
$id = get_id($element);
if (is_numeric($id)) $accumulator[] = $id;
return $accumulator;
},
array())
NOTE: My implementations of array_map and array_filter above won't behave exactly like PHP's, since my array_map can only handle one array at a time and my array_filter won't use "empty" as its default $function. Also, neither will preserve keys.
注意:我上面的array_map 和array_filter 的实现与PHP 的表现不同,因为我的array_map 一次只能处理一个数组,而我的array_filter 不会使用“空”作为其默认的$ 函数。此外,两者都不会保留密钥。
It's not difficult to make them behave like PHP's, but I felt that these complications would make the core idea harder to spot.
让它们表现得像 PHP 并不难,但我觉得这些复杂性会使核心思想更难以发现。
回答by slevy1
The following revision seeks to more clearly delineate PHP's array_filer(), array_map(), and array_walk(), all of which originate from functional programming:
以下修订旨在更清楚地描述 PHP 的 array_filer()、array_map() 和 array_walk(),所有这些都源自函数式编程:
array_filter() filters out data, producing as a result a new array holding only the desired items of the former array, as follows:
array_filter() 过滤掉数据,结果产生一个新数组,只包含前一个数组的所需项,如下所示:
<?php
$array = array(1, "apples",2, "oranges",3, "plums");
$filtered = array_filter( $array, "ctype_alpha");
var_dump($filtered);
?>
live code here
现场代码在这里
All numeric values are filtered out of $array, leaving $filtered with only types of fruit.
所有数值都从 $array 中过滤掉,只留下 $filtered 的水果类型。
array_map() also creates a new array but unlike array_filter() the resulting array contains everyelement of the input $filtered but with altered values, owing to applying a callback to each element, as follows:
array_map() 还创建了一个新数组,但与 array_filter() 不同,由于对每个元素应用回调,结果数组包含输入 $filtered 的每个元素,但具有更改的值,如下所示:
<?php
$nu = array_map( "strtoupper", $filtered);
var_dump($nu);
?>
live code here
现场代码在这里
The code in this case applies a callback using the built-in strtoupper() but a user-defined function is another viable option, too. The callback applies to every item of $filtered and thereby engenders $nu whose elements contain uppercase values.
这种情况下的代码使用内置的 strtoupper() 应用回调,但用户定义的函数也是另一个可行的选择。回调适用于 $filtered 的每个项目,从而生成元素包含大写值的 $nu。
In the next snippet, array walk() traverses $nu and makes changes to each element vis a vis the reference operator '&'. The changes occur without creating an additional array. Every element's value changes in place into a more informative string specifying its key, category and value.
在下一个片段中,数组 walk() 遍历 $nu 并通过引用运算符“&”对每个元素进行更改。无需创建额外的数组即可进行更改。每个元素的值都会更改为一个信息更丰富的字符串,指定其键、类别和值。
<?php
$f = function(&$item,$key,$prefix) {
$item = "$key: $prefix: $item";
};
array_walk($nu, $f,"fruit");
var_dump($nu);
?>
See demo
看演示
Note: the callback function with respect to array_walk() takes two parameters which will automatically acquire an element's value and its key and in that order, too when invoked by array_walk(). (See more here).
注意:关于 array_walk() 的回调函数有两个参数,当 array_walk() 调用时,这两个参数将自动获取元素的值及其键,并按照该顺序。(在此处查看更多信息)。