Les autres réponses démontrent assez bien la différence entre array_walk (modification sur place) et array_map (retour de la copie modifiée). Cependant, ils ne mentionnent pas vraiment array_reduce, ce qui est un moyen éclairant de comprendre array_map et array_filter.
La fonction array_reduce prend un tableau, une fonction à deux arguments et un 'accumulateur', comme ceci:
array_reduce(array('a', 'b', 'c', 'd'),
'my_function',
$accumulator)
Les éléments du tableau sont combinés avec l'accumulateur un par un, en utilisant la fonction donnée. Le résultat de l'appel ci-dessus est le même que celui-ci:
my_function(
my_function(
my_function(
my_function(
$accumulator,
'a'),
'b'),
'c'),
'd')
Si vous préférez penser en termes de boucles, c'est comme faire ce qui suit (je l'ai en fait utilisé comme solution de rechange lorsque array_reduce n'était pas disponible):
function array_reduce($array, $function, $accumulator) {
foreach ($array as $element) {
$accumulator = $function($accumulator, $element);
}
return $accumulator;
}
Cette version en boucle explique pourquoi j'ai appelé le troisième argument un «accumulateur»: nous pouvons l'utiliser pour accumuler des résultats à chaque itération.
Alors qu'est-ce que cela a à voir avec array_map et array_filter? Il s'avère qu'ils sont tous deux un type particulier de array_reduce. Nous pouvons les implémenter comme ceci:
array_map($function, $array) === array_reduce($array, $MAP, array())
array_filter($array, $function) === array_reduce($array, $FILTER, array())
Ignorez le fait que array_map et array_filter prennent leurs arguments dans un ordre différent; c'est juste une autre bizarrerie de PHP. Le point important est que le côté droit est identique à l'exception des fonctions que j'ai appelées $ MAP et $ FILTER. Alors, à quoi ressemblent-ils?
$MAP = function($accumulator, $element) {
$accumulator[] = $function($element);
return $accumulator;
};
$FILTER = function($accumulator, $element) {
if ($function($element)) $accumulator[] = $element;
return $accumulator;
};
Comme vous pouvez le voir, les deux fonctions récupèrent l'accumulateur $ et le renvoient à nouveau. Il existe deux différences dans ces fonctions:
- $ MAP s'ajoutera toujours à $ accumulator, mais $ FILTER ne le fera que si $ function ($ element) est TRUE.
- $ FILTER ajoute l'élément d'origine, mais $ MAP ajoute $ function ($ element).
Notez que cela est loin d'être trivial inutile; nous pouvons l'utiliser pour rendre nos algorithmes plus efficaces!
Nous pouvons souvent voir du code comme ces deux exemples:
// Transform the valid inputs
array_map('transform', array_filter($inputs, 'valid'))
// Get all numeric IDs
array_filter(array_map('get_id', $inputs), 'is_numeric')
L'utilisation de array_map et array_filter au lieu de boucles rend ces exemples assez agréables. Cependant, il peut être très inefficace si $ inputs est grand, car le premier appel (carte ou filtre) traversera $ inputs et construira un tableau intermédiaire. Ce tableau intermédiaire est transmis directement dans le deuxième appel, qui traversera à nouveau le tout, puis le tableau intermédiaire devra être récupéré.
Nous pouvons nous débarrasser de ce tableau intermédiaire en exploitant le fait que array_map et array_filter sont tous deux des exemples de array_reduce. En les combinant, nous n'avons à parcourir $ inputs qu'une seule fois dans chaque exemple:
// 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())
REMARQUE: Mes implémentations de array_map et array_filter ci-dessus ne se comporteront pas exactement comme PHP, car mon array_map ne peut gérer qu'un seul tableau à la fois et mon array_filter n'utilisera pas "empty" comme fonction $ par défaut. De plus, aucun ne conservera les clés.
Il n'est pas difficile de les faire se comporter comme PHP, mais je sentais que ces complications rendraient l'idée de base plus difficile à repérer.