提问人: 提问时间:8/8/2010 最后编辑:HoldOffHunger 更新时间:6/23/2021 访问量:207644
array_map、array_walk和array_filter之间的区别
Difference between array_map, array_walk and array_filter
问:
和 到底有什么区别。我从文档中可以看到,您可以传递回调函数来对提供的数组执行操作。但我似乎没有发现它们之间有什么特别的区别。array_map
array_walk
array_filter
它们执行相同的操作吗?
它们可以互换使用吗?
如果它们完全不同,我将不胜感激您提供说明性示例的帮助。
答:
- 更改值:
array_map
不能更改输入数组中的值,而array_walk
可以;特别是,array_map
从不改变其论点。
- 阵列键访问:
array_map
不能使用数组键进行操作,array_walk
可以。- 返回值:
array_map
返回一个新数组,array_walk
只返回 .因此,如果您不想因遍历一个数组而创建数组,则应使用array_walk
。true
- 迭代多个数组:
array_map
还可以接收任意数量的数组,并且可以并行迭代它们,而array_walk
只在一个数组上运行。- 将任意数据传递给回调:
array_walk
可以接收一个额外的任意参数来传递给回调。自 PHP 5.3 以来,这几乎无关紧要(当引入匿名函数时)。- 返回数组的长度:
- 生成的数组的长度与最大输入数组的长度相同; 不返回数组,但同时不能改变原始数组的元素数量;
array_filter
根据过滤函数仅选取数组元素的子集。它确实保留了密钥。array_map
array_walk
例:
<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>
结果:
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
)
评论
array_map(callback($key, $value), array_keys($array), $array)
从文档中,
bool array_walk ( array &$array , callback $funcname [, mixed $userdata ] ) <-return bool
array_walk 接受一个数组和一个函数,并通过用 替换每个元素 x 来修改它。F
F(x)
数组array_map(回调$callback, 数组 $arr 1 [, 数组 $... ] )<返回数组
array_map执行完全相同的操作,只是它不会就地修改,而是返回一个包含转换元素的新数组。
array array_filter ( array $input [, callback $callback ] )<-return 数组
array_filter函数 ,而不是转换元素,将删除任何不真实的元素F
F(x)
评论
array_walk
array_map
将函数映射到数据数组的思想来自函数式编程。你不应该把它看作是一个循环,它对数组的每个元素都调用一个函数(即使它是这样实现的)。它应该被认为是将函数独立应用于数组中的每个元素。array_map
foreach
从理论上讲,函数映射之类的事情可以并行完成,因为应用于数据的函数应该只影响数据,而不是全局状态。这是因为可以选择将函数应用于 IN 中的项目的任何顺序(即使在 PHP 中它没有)。array_map
array_walk
另一方面,它处理数据数组的方法完全相反。它不是单独处理每个项目,而是使用状态 () 并可以就地编辑项目(很像 foreach 循环)。由于每次应用一个项目时,它都可能改变程序的全局状态,因此需要一种正确的方法来处理项目。&$userdata
$funcname
回到PHP领域,它们几乎相同,只是让你对数据的迭代有更多的控制,通常用于就地“更改”数据,而不是返回一个新的“更改”数组。array_map
array_walk
array_walk
array_filter
实际上是(或)的应用程序,它或多或少只是为了方便而提供的。array_walk
array_reduce
评论
array_filter()
array_walk()
下面的修订试图更清楚地描述PHP的array_filer()、array_map()和array_walk(),它们都源自函数式编程:
array_filter() 过滤掉数据,从而生成一个新数组,该数组仅包含前一个数组的所需项目,如下所示:
<?php
$array = array(1, "apples",2, "oranges",3, "plums");
$filtered = array_filter( $array, "ctype_alpha");
var_dump($filtered);
?>
实时代码在这里
所有数值都从$array中过滤掉,只留下$filtered水果类型。
array_map() 也创建一个新数组,但与 array_filter() 不同的是,生成的数组包含输入$filtered的每个元素,但由于对每个元素应用回调,因此值发生了变化,如下所示:
<?php
$nu = array_map( "strtoupper", $filtered);
var_dump($nu);
?>
实时代码在这里
在这种情况下,代码使用内置的 strtoupper() 应用回调,但用户定义的函数也是另一个可行的选项。回调适用于$filtered的每个项目,从而生成其元素包含大写值$nu。
在下一个代码段中,数组 walk() 遍历$nu,并对引用运算符 '&' 的每个元素进行更改。更改不会创建其他数组。每个元素的值都会就地更改为信息量更大的字符串,指定其键、类别和值。
<?php
$f = function(&$item,$key,$prefix) {
$item = "$key: $prefix: $item";
};
array_walk($nu, $f,"fruit");
var_dump($nu);
?>
观看演示
注意:关于 array_walk() 的回调函数采用两个参数,当 array_walk() 调用时,它们将自动获取元素的值及其键,并且按此顺序获取。(在此处查看更多内容)。
评论
$lambda
$callback
$filtered = array_filter($array, 'ctype_alpha');
$nu = array_map('strtoupper', $filtered);
其他答案很好地说明了array_walk(就地修改)和array_map(返回修改后的副本)之间的区别。然而,他们并没有真正提到array_reduce,这是理解array_map和array_filter的一种启发性方式。
array_reduce函数接受一个数组、一个双参数函数和一个“累加器”,如下所示:
array_reduce(array('a', 'b', 'c', 'd'),
'my_function',
$accumulator)
使用给定的函数,数组的元素一次与累加器组合一个。上述调用的结果与执行此操作的结果相同:
my_function(
my_function(
my_function(
my_function(
$accumulator,
'a'),
'b'),
'c'),
'd')
如果您更喜欢从循环的角度来考虑,就像执行以下操作一样(当array_reduce不可用时,我实际上将其用作后备):
function array_reduce($array, $function, $accumulator) {
foreach ($array as $element) {
$accumulator = $function($accumulator, $element);
}
return $accumulator;
}
这个循环版本清楚地说明了为什么我将第三个参数称为“累加器”:我们可以使用它来累积每次迭代的结果。
那么这与array_map和array_filter有什么关系呢?事实证明,他们都是一种特殊的array_reduce。我们可以这样实现它们:
array_map($function, $array) === array_reduce($array, $MAP, array())
array_filter($array, $function) === array_reduce($array, $FILTER, array())
忽略这样一个事实,即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;
};
如您所见,这两个函数都接收$accumulator并再次返回。这些函数有两个区别:
- $MAP 将始终附加到 $accumulator,但仅当 $function($element) 为 TRUE 时,$FILTER才会这样做。
- $FILTER 附加原始元素,但$MAP附加 $function($element)。
请注意,这远非无用的琐事;我们可以用它来使我们的算法更有效率!
我们经常可以看到以下两个示例的代码:
// Transform the valid inputs
array_map('transform', array_filter($inputs, 'valid'))
// Get all numeric IDs
array_filter(array_map('get_id', $inputs), 'is_numeric')
使用 array_map 和 array_filter 而不是循环使这些示例看起来非常漂亮。但是,如果$inputs很大,则效率可能非常低,因为第一次调用(映射或过滤器)将遍历$inputs并构建中间数组。这个中间数组被直接传递到第二个调用中,它将再次遍历整个过程,然后需要对中间数组进行垃圾回收。
我们可以通过利用 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())
注意:我对上述array_map和array_filter的实现不会完全像PHP一样,因为我的array_map一次只能处理一个数组,而我的array_filter不会使用“空”作为其默认$function。此外,两者都不会保留密钥。
让它们表现得像PHP一样并不难,但我觉得这些复杂性会使核心思想更难被发现。
评论