array_map,array_walk和array_filter之间的区别

array_maparray_walkarray_filter之间的区别究竟是什么。 从文档中我可以看到,你可以传递一个callback函数来对提供的数组执行操作。 但我似乎没有发现他们之间的任何特别的区别。

他们做同样的事情吗?
它们可以互换使用吗?

如果他们完全不同,我将不胜感激您的帮助。

  • array_map没有附带的影响,而array_walk可以; 特别是, array_map永远不会改变它的参数。
  • array_map不能使用数组键, array_walk可以。
  • array_map返回一个数组, array_walk只返回true / false 。 因此,如果你不想因为遍历一个数组而创build一个数组,你应该使用array_walk
  • array_map也可以接收任意数量的数组,而array_walk只能在一个数组上运行。
  • array_walk可以接收一个额外的任意parameter passing给callback。 这从PHP5.3(当匿名函数被引入时)几乎是不相干的。
  • array_map / array_walk的结果数组与参数的元素数相同; array_filter根据过滤函数仅挑选数组的元素的一个子集。 它确实保存了密钥。

例:

 <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成一个在数组的每个元素上调用一个函数的foreach循环(尽pipe这是如何实现的)。 它应该被认为是独立地将函数应用于arrays中的每个元素。

从理论上说,函数映射这样的东西可以并行完成,因为应用于数据的函数只应该影响数据而不影响全局状态。 这是因为array_map可以select将函数应用于项目的任何顺序(即使在PHP中它不)。

另一方面, array_walk与处理数据数组完全相反。 它不是单独处理每个项目,而是使用一个状态( &$userdata ),并且可以编辑项目(就像foreach循环一样)。 由于每次项目具有$funcname应用程序,它可能会改变程序的全局状态,因此需要一个正确的方式来处理项目。

在PHP领域, array_maparray_walk几乎是相同的,除了array_walk可以更好地控制数据的迭代,通常用于“就地”更改数据和返回新的“更改”数组。

array_filter实际上是array_walk (或array_reduce )的一个应用程序,为了方便起见,它或多或less是或多或less的。

从文档中,

bool array_walk(array&$ array,callback $ funcname [,mixed $ userdata])<-return bool

array_walk需要一个数组和一个函数F并用F(x)代替每个元素x来修改它。

array array_map(callback $ callback,array $ arr1 [,array $ …]) – 返回数组

array_map执行完全相同的事情, 除了不是就地修改它将返回一个新的数组与转换元素。

array array_filter(array $ input [,callback $ callback])< – 返回数组

带有函数F array_filter ,而不是转换元素,将删除任何F(x)不为真的元素

其他答案很好地展示了array_walk(in-place modification)和array_map(return modified copy)之间的区别。 但是,他们并没有真正提到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有什么关系呢? 事实certificate,它们都是一种特殊的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中再次返回。 这些function有两个区别:

  • $ MAP将总是附加到$ accumulator,但$ FILTER只会在$ function($ element)为TRUE的时候这样做。
  • $ FILTER追加原始元素,但$ MAP追加$函数($元素)。

请注意,这远不是毫无用处的琐事; 我们可以使用它来使我们的algorithm更有效率!

我们经常可以看到这样两个例子的代码:

 // 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代替循环使得这些例子看起来相当不错。 然而,如果$input很大,可能会非常低效,因为第一个调用(map或filter)将遍历$input并构build一个中间数组。 这个中间数组被直接传入第二个调用,它将遍历整个事情,然后中间数组将被垃圾收集。

我们可以通过利用array_map和array_filter都是array_reduce的例子来摆脱这个中间数组。 通过结合它们,我们在每个例子中只需要遍历$input一次:

 // 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不会使用“empty”作为它的默认$函数。 而且,也不会保存密钥。

让它们像PHP一样行事并不难,但我觉得这些复杂性会让核心想法更难以发现。

下面的修订旨在更清楚地描述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中过滤出来,只保留$只用水果types过滤。

array_map()也创build一个新的数组,但不同于array_filter(),结果数组包含input$ filter的每个元素,但是由于对每个元素应用callback,

 <?php $nu = array_map( "strtoupper", $filtered); var_dump($nu); ?> 

现场代码在这里

本例中的代码使用内置的strtoupper()应用callback,但用户定义的函数也是另一个可行的选项。 该callback适用于每个$ filtered的项目,从而产生$ nu,其元素包含大写值。

在下一个片段中,数组walk()遍历$ nu,并对每个元素进行相对于引用运算符“&”的更改。 更改发生时不创build一个额外的数组。 每个元素的值都会更改为更具信息性的string,以指定其关键字,类别和值。

 <?php $f = function(&$item,$key,$prefix) { $item = "$key: $prefix: $item"; }; array_walk($nu, $f,"fruit"); var_dump($nu); ?> 

看演示

注意:关于array_walk()的callback函数有两个参数,它们会在array_walk()调用时自动获得一个元素的值和它的键值。 (请看这里 )