Différence entre la carte de tableau, la promenade de tableau et le filtre de tableau

Quelle est exactement la différence entre array_map, array_walk et array_filter. Ce que je pouvais voir de la documentation est que vous pourriez passer une fonction de rappel pour effectuer une action sur le tableau fourni. Mais je ne semble pas trouver de différence entre eux.

Font-ils la même chose?
Peuvent - ils être utilisés de manière interchangeable?

J'apprécierais votre aide avec l'exemple illustratif s'ils sont différents du tout.

327
demandé sur Gras Double 2010-08-08 02:19:35

5 réponses

  • Modification Des Valeurs:
    • array_map impossible de modifier les valeurs à l'intérieur du ou des tableaux d'entréearray_walk can; en particulier, array_map ne change jamais ses arguments.
  • Accès Aux Clés Du Tableau:
  • Valeur De Retour:
    • array_map renvoie un nouveau tableau, array_walk renvoie uniquement true/false. Par conséquent, si vous n'avez pas souhaitez créer un tableau comme une suite de parcours d'un tableau, vous devez utiliser array_walk.
  • Itération De Plusieurs Tableaux:
    • array_map peut également recevoir un nombre arbitraire de tableaux et il peut parcourir, en parallèle, tout en array_walk ne fonctionne que sur un seul.
  • passer des données arbitraires au rappel:
    • array_walk peut recevoir un paramètre arbitraire supplémentaire à passer au rappel. La plupart du temps hors de propos depuis PHP 5.3 (quand fonctions anonymes ont été introduites).
  • Longueur du tableau retourné:
    • Le tableau résultant de array_map a la même longueur que celle du plus grand tableau d'entrée; array_walk ne pas retourner un tableau, mais en même temps il ne peut pas modifier le nombre d'éléments du tableau d'origine; array_filter sélectionne un sous-ensemble des éléments de la matrice selon une fonction de filtrage. Il ne conserver la touches.

Exemple:

<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>

Résultat:

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
)
487
répondu Artefacto 2018-07-06 20:35:07

L'idée de cartographie une fonction de tableau de données provient de la programmation fonctionnelle. Vous ne devriez pas penser à array_map comme une boucle foreach qui appelle une fonction sur chaque élément du tableau (même si c'est comme ça qu'elle est implémentée). Il devrait être considéré comme appliquant la fonction à chaque élément du tableau indépendamment.

En théorie, des choses telles que le mappage de fonction peuvent être faites en parallèle puisque la fonction appliquée aux données ne devrait affecter que les données et non l'état global. C'est parce qu'un array_map pourrait choisir n'importe quel ordre dans lequel appliquer la fonction aux éléments (même si en PHP ce n'est pas le cas).

array_walk d'autre part, c'est l'approche exactement opposée à la gestion des tableaux de données. Au lieu de gérer chaque élément séparément, il utilise un État (&$userdata) et peut modifier l'élément en place (un peu comme une boucle foreach). Comme chaque fois qu'un élément a le $funcname appliqué, il pourrait changer l'état global du programme et nécessite donc un seul corriger façon de traiter les éléments.

Retour en PHP land, array_map et array_walk sont presque identiques sauf que array_walk vous donne plus de contrôle sur l'itération des données et est normalement utilisé pour "changer" les données en place vs renvoyer un nouveau tableau "changé".

array_filter est vraiment une application de array_walk (ou array_reduce) et plus ou moins juste pour votre confort.

85
répondu Kendall Hopkins 2017-06-18 08:45:11

De la documentation,

Bool array_walk ( array &$array , callback $funcname [, mixed $userdata ] )

Array_walk prend un tableau et une fonction de F et la modifie en remplaçant chaque élément x de F(x).

Tableau array_map ( callback $ callback , tableau $ arr1 [, tableau $... ])

Array_map fait exactement la même chose sauf qu'au lieu de modifier sur place il retournera un nouveau tableau avec les éléments transformés.

Tableau array_filter ( array $input [, rappel $rappel ] )

Array_filter avec la fonction F, au lieu de transformer les éléments, va supprimer tous les éléments pour lesquels F(x) n'est pas vrai

36
répondu Steven Schlansker 2011-06-01 13:20:13

Les autres réponses démontrent assez bien la différence entre array_walk (modification sur place) et array_map (copie modifiée de retour). Cependant, ils ne mentionnent pas vraiment array_reduce, 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 à la fois, en utilisant la fonction donnée. Résultat de l'appel ci-dessus est le même que de faire ceci:

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 (j'ai effectivement utilisé ceci comme une solution de repli quand 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 clairement 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 les deux un particulier type 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())

Ignorer 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 sauf pour les 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 prennent l'accumulateur $et le renvoient à nouveau. Il y a deux différences dans ces fonctions:

  • $MAP sera toujours ajouté à $ 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 c'est loin d'être une anecdote 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 plutôt agréables. Cependant, cela peut être très inefficace si $inputs est grand, puisque le premier appel (map ou filter) traversera $inputs et construira un tableau intermédiaire. Ce tableau intermédiaire est passé directement dans le deuxième appel, qui traversera à nouveau le tout,puis le tableau intermédiaire devra être collecté.

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 qu'à traverse $entrées une 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())

NOTE: mes implémentations de array_map et array_filter ci-dessus ne se comporteront pas exactement comme PHP, puisque mon array_map ne peut gérer qu'un tableau à la fois et mon array_filter n'utilisera pas "empty" comme fonction $par défaut. En outre, ni l'un ni l'autre ne préservera les clés.

Il n'est pas difficile de les faire se comporter comme PHP, mais j'ai senti que ces complications rendraient l'idée de base plus difficile à repérer.

16
répondu Warbo 2014-05-01 17:51:07

La révision suivante cherche à délimiter plus clairement array_filer(), array_map () et array_walk () de PHP, qui proviennent tous de la programmation fonctionnelle:

Array_filter() filtre de données, produisant en conséquence, un nouveau tableau contenant uniquement les éléments souhaités de l'ancien tableau, comme suit:

<?php
$array = array(1, "apples",2, "oranges",3, "plums");

$filtered = array_filter( $array, "ctype_alpha");
var_dump($filtered);
?>

Code En Direct ici

Toutes les valeurs numériques sont filtrées hors de $ array, laissant $filtré avec seulement des types de fruits.

Array_map() crée également un nouveau array mais contrairement à array_filter () le tableau résultant contient chaque élément de l'entrée $ filtered mais avec des valeurs modifiées, en raison de l'application d'un rappel à chaque élément, comme suit:

<?php

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

Code EN DIRECT ici

Le code dans ce cas applique un rappel en utilisant le strtoupper () intégré mais une fonction définie par l'utilisateur est également une autre option viable. Le rappel s'applique à chaque élément de $filtered et engendre ainsi $nu dont les éléments contiennent des majuscules valeur.

Dans l'extrait suivant, array walk() traverse $ nu et modifie chaque élément par rapport à l'opérateur de référence'&'. Les modifications se produisent sans créer de tableau supplémentaire. La valeur de chaque élément change en place dans une chaîne plus informative spécifiant sa clé, sa catégorie et sa valeur.

<?php

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

Voir démo

Note: la fonction de rappel par rapport à array_walk() prend deux paramètres qui acquerront automatiquement la valeur d'un élément et sa clé et dans cet ordre, aussi lorsqu'il est invoqué par array_walk (). (Voir plus ici).

1
répondu slevy1 2017-05-23 20:39:01