разница между array\_map, array\_walk и array\_filter

<p>в чем разница между <code>array\_map</code>, <code>array\_walk</code> и <code>array\_filter</code>. из документации видно, что вы можете передать функцию обратного вызова для выполнения действия над предоставленным массивом. но я не вижу особой разницы между ними.</p><p>они выполняют то же самое?<br> могут ли они быть взаимозаменяемыми?</p><p>буду признателен за помощь с иллюстративным примером, если они вообще отличаются.</p>

<ul> <li>изменение значений: <ul> <li> <a href="http://php.net/array\_map"><code>array\_map</code></a> не может изменить значения внутри входных массивов, в то время как <a href="http://php.net/array\_walk"><code>array\_walk</code></a> может; в частности, <a href="http://php.net/array\_map"><code>array\_map</code></a> никогда не меняет своих аргументов.</li> </ul> </li> <li>доступ к массиву ключей: <ul> <li> <a href="http://php.net/array\_map"><code>array\_map</code></a> не может работать с ключами массива, <a href="http://php.net/array\_walk"><code>array\_walk</code></a> может.</li> </ul> </li> <li>возвращаемое значение: <ul> <li> <a href="http://php.net/array\_map"><code>array\_map</code></a> возвращает новый массив, <a href="http://php.net/array\_walk"><code>array\_walk</code></a> возвращает только <code>true</code>. следовательно, если вы не хотите создавать массив в результате обхода одного массива, вы должны использовать <a href="http://php.net/array\_walk"><code>array\_walk</code></a> .</li> </ul> </li> <li>итерация нескольких массивов: <ul> <li> <a href="http://php.net/array\_map"><code>array\_map</code></a> также может принимать произвольное количество массивов и может проходить их параллельно, в то время как <a href="http://php.net/array\_walk"><code>array\_walk</code></a> работает только с одним.</li> </ul> </li> <li>передача произвольных данных в обратный вызов: <ul> <li> <a href="http://php.net/array\_walk"><code>array\_walk</code></a> может получить дополнительный произвольный параметр для передачи в обратный вызов. это в основном не имеет значения, поскольку php 5.3 (когда <a href="http://nl3.php.net/manual/en/functions.anonymous.php">анонимные функции</a> были введены).</li> </ul> </li> <li>длина возвращаемого массива: <ul> <li>результирующий массив <code>array\_map</code> имеет ту же длину, что и самый большой входной массив; <code>array\_walk</code> не возвращает массив, но в то же время не может изменять количество элементов исходного массива; <a href="http://php.net/array\_filter"><code>array\_filter</code></a> выбирает только подмножество элементов массива в соответствии с функцией фильтрации. это сохраняет ключи.</li> </ul> </li> </ul><p>пример:</p><pre><code><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; }) ); ?>  результат: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 ) 

идея <a href="http://en.wikipedia.org/wiki/map_(higher-order_function)">отображение функции в массив данных происходит из функционального программирования. вы не должны думать о array_map как о цикле foreach, который вызывает функцию для каждого элемента массива (даже при том, как это реализовано). это следует рассматривать как применение функции к каждому элементу в массиве независимо.теоретически такие вещи, как отображение функций, могут выполняться параллельно, поскольку функция, применяемая к данным, должна влиять только на данные, а не на глобальное состояние. это связано с тем, что array_map может выбирать любой порядок, в котором применяется функция к элементам (даже если в php это не так).array_walk с другой стороны - это совершенно противоположный подход к обработке массивов данных. вместо того, чтобы обрабатывать каждый элемент отдельно, он использует состояние (&$userdata</code>) и может редактировать элемент на месте (так же, как цикл foreach). поскольку каждый раз, когда к элементу применяется <code>$funcname, он может изменить глобальное состояние программы, и для этого требуется один  правильный  способ обработки элементов. ,.вернувшись в php сушу, array_map и array_walk практически идентичны, за исключением того, что array_walk дает вам больший контроль над итерацией данных и обычно используется для "изменения" данных на месте по сравнению с возвратом нового "измененного" массива.array_filter на самом деле является приложением array_walk (или array_reduce) и более-менее просто предоставлен для удобства.

из документации,<blockquote> bool array_walk (array & $ array, обратный вызов $ funcname [ mixed $ userdata]) <-retol bool</p> </blockquote><p> <a href="http://php.net/manual/en/function.array-walk.php">array\_walk</a> принимает массив и функцию <code>f</code> и изменяет ее, заменяя каждый элемент x на <code>f(x)</code>.</p><blockquote> <p>массив array\_map (обратный вызов $ callback, массив $ arr1 [ массив $ ...]) <- вернуть массив </blockquote> <a href="http://php.net/manual/en/function.array-map.php">array_map делает то же самое <strong>, за исключением </strong>, что вместо изменения на месте он возвращает новый массив с преобразованными элементами.<blockquote> массив array_filter (массив $ input [ callback $ callback]) <- вернуть массив </blockquote> <a href="http://php.net/manual/en/function.array-filter.php">array_filter с функцией f вместо преобразования элементов удалит все элементы, для которых f(x) не соответствует действительности

другие ответы достаточно хорошо демонстрируют разницу между array_walk (модификация на месте) и array_map (вернуть измененную копию). тем не менее, они на самом деле не упоминают array_reduce, которая является отличным способом понять array_map и array_filter.функция array_reduce принимает массив, функцию с двумя аргументами и "аккумулятор", например:array_reduce(array('a', 'b', 'c', 'd'), 'my_function', $accumulator) </code></pre><p>элементы массива объединяются с аккумулятором по одному, используя данную функцию. результат вышеприведенного вызова такой же, как при выполнении этого:</p><pre><code>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; }; </code></pre><p>как видите, обе функции берут $ аккумулятор и возвращают его снова. есть два различия в этих функциях: $ map всегда будет добавляться к $ накопителю, но $ filter будет делать это только в том случае, если $ function ($ element) имеет значение true.</li> <li>$ filter добавляет исходный элемент, но $ map добавляет функцию $ ($ element).</li> </ul><p>обратите внимание, что это далеко не бесполезные мелочи; мы можем использовать его, чтобы сделать наши алгоритмы более эффективными!</p><p>мы часто видим код, подобный этим двум примерам:</p><pre><code>// transform the valid inputs array\_map('transform', array\_filter($inputs, 'valid')) // get all numeric ids array_filter(array_map('get_id', $inputs), 'is\_numeric') </code></pre><p>использование array\_map и array\_filter вместо циклов делает эти примеры довольно привлекательными. однако это может быть очень неэффективно, если $ input велико, так как первый вызов (map или filter) будет проходить по $ input и создавать промежуточный массив. этот промежуточный массив передается прямо во второй вызов, который снова будет проходить через все это, затем промежуточный массив необходимо будет собрать мусором.</p><p>мы можем избавиться от этого промежуточного массива, используя тот факт, что array\_map и array\_filter являются примерами array\_reduce. объединив их, нам нужно пройти через входные данные только один раз в каждом примере</p><pre><code>// 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()) </code></pre><p>примечание. мои реализации 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); ?> живой код <a href="https://3v4l.org/9sdgu">здесь все числовые значения отфильтрованы из массива $, в результате чего $ фильтруется только с фруктами.array_map () также создает новый массив, но в отличие от array_filter () результирующий массив содержит  каждый  элемент входного $ фильтрованного, но с измененными значениями, вследствие применения обратный вызов для каждого элемента, как показано ниже:</p><pre><code><?php $nu = array_map( "strtoupper", $filtered); var\_dump($nu); ?> живой код <a href="https://3v4l.org/r8cve">здесь код в этом случае применяет обратный вызов, используя встроенную функцию strtoupper (), но пользовательская функция также является еще одним приемлемым вариантом. обратный вызов применяется к каждому элементу $ отфильтрованного и тем самым порождает $ nu, элементы которого содержат значения в верхнем регистре.в следующем фрагменте массив walk () обходит $ nu и вносит изменения в каждый элемент в отношении оператора ссылки '&'. изменения происходят без создания дополнительного массива. значение каждого элемента меняется на место в более информативную строку с указанием его ключа, категории и значения.</p><pre><code><?php $f = function(&$item,$key,$prefix) { $item = "$key: $prefix: $item"; }; array\_walk($nu, $f,"fruit"); var\_dump($nu); ?> </code></pre><p>смотрите <a href="https://3v4l.org/unevv">демо</a> </p><p>примечание: функция обратного вызова относительно array\_walk () принимает два параметра, которые автоматически получают значение элемента и его ключ, и в том же порядке, когда они вызываются array\_walk (). (подробнее <a href="http://php.net/manual/en/function.array-walk.php">здесь</a> ).</p>