421 Stimmen

Unterschied zwischen array_map, array_walk und array_filter

Was genau ist der Unterschied zwischen array_map , array_walk y array_filter . Aus der Dokumentation konnte ich ersehen, dass man eine Callback-Funktion übergeben könnte, um eine Aktion mit dem übergebenen Array durchzuführen. Aber ich scheine keinen besonderen Unterschied zwischen ihnen zu finden.

Erfüllen sie dieselbe Aufgabe?
Können sie austauschbar verwendet werden?

Ich wäre Ihnen dankbar, wenn Sie mir ein anschauliches Beispiel geben könnten, falls es überhaupt Unterschiede gibt.

652voto

Artefacto Punkte 93200
  • Werte im Wandel:
    • array_map kann die Werte in den Eingabefeldern nicht ändern, während array_walk können; insbesondere, array_map ändert niemals seine Argumente.
  • Array Keys Zugriff:
  • Rückgabewert:
    • array_map gibt ein neues Array zurück, array_walk kehrt nur zurück true . Wenn Sie also kein Array als Ergebnis der Durchquerung eines Arrays erstellen wollen, sollten Sie array_walk .
  • Iteration mehrerer Arrays:
    • array_map kann auch eine beliebige Anzahl von Arrays empfangen und parallel über sie iterieren, während array_walk arbeitet nur mit einem.
  • Übergabe beliebiger Daten an Callback:
    • array_walk kann einen zusätzlichen, beliebigen Parameter erhalten, der an den Callback übergeben wird. Dies ist größtenteils irrelevant seit PHP 5.3 (wenn anonyme Funktionen eingeführt wurden).
  • Länge des zurückgegebenen Arrays:
    • Die resultierende Reihe von array_map hat die gleiche Länge wie das größte Eingabefeld; array_walk gibt kein Array zurück, kann aber gleichzeitig die Anzahl der Elemente des ursprünglichen Arrays nicht verändern; array_filter wählt nur eine Teilmenge der Elemente des Arrays gemäß einer Filterfunktion aus. Dabei bleiben die Schlüssel erhalten.

Beispiel:

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

Ergebnis:

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
)

99voto

Kendall Hopkins Punkte 41041

Die Idee der Kartierung eine Funktion zu einem Array von Daten stammt aus der funktionalen Programmierung. Sie sollten nicht darüber nachdenken array_map als foreach Schleife, die eine Funktion für jedes Element des Arrays aufruft (auch wenn das so implementiert ist). Man sollte sich vorstellen, dass die Funktion auf jedes Element des Arrays unabhängig angewendet wird.

Theoretisch können solche Dinge wie die Funktionszuordnung parallel durchgeführt werden, da die auf die Daten angewandte Funktion NUR die Daten und NICHT den globalen Zustand beeinflussen sollte. Dies liegt daran, dass eine array_map könnte eine beliebige Reihenfolge wählen, in der die Funktion auf die Elemente angewendet wird (auch wenn das in PHP nicht der Fall ist).

array_walk auf der anderen Seite ist es der genau gegenteilige Ansatz für den Umgang mit Arrays von Daten. Anstatt jedes Element einzeln zu behandeln, wird ein Zustand ( &$userdata ) und kann das Element an Ort und Stelle bearbeiten (ähnlich wie eine foreach-Schleife). Da jedes Mal, wenn ein Element die $funcname angewandt wird, könnte sie den globalen Zustand des Programms ändern und erfordert daher eine einzige richtig Art der Verarbeitung der Artikel.

Zurück im PHP-Land, array_map y array_walk sind fast identisch, außer array_walk gibt Ihnen mehr Kontrolle über die Iteration von Daten und wird in der Regel verwendet, um die Daten an Ort und Stelle zu "ändern", anstatt ein neues "geändertes" Array zurückzugeben.

array_filter ist eigentlich eine Anwendung von array_walk (o array_reduce ) und diente mehr oder weniger nur der Bequemlichkeit.

45voto

Steven Schlansker Punkte 35955

Aus der Dokumentation,

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

array_walk nimmt ein Array und eine Funktion F und modifiziert es, indem es jedes Element x durch F(x) .

array array_map ( Rückruf $callback , array $arr1 [, array $... ] )<-zurück array

array_map macht genau das Gleiche außer dass es anstelle einer Änderung an Ort und Stelle ein neues Array mit den umgewandelten Elementen zurückgibt.

array array_filter ( array $input [, callback $callback ] )<-zurück array

array_filter mit Funktion F anstatt die Elemente umzuwandeln, werden alle Elemente entfernt, für die F(x) ist nicht wahr

25voto

Warbo Punkte 2482

Die anderen Antworten demonstrieren den Unterschied zwischen array_walk (Änderung an Ort und Stelle) und array_map (modifizierte Kopie zurückgeben) recht gut. Sie erwähnen jedoch nicht wirklich array_reduce Dies ist ein erhellender Weg, um array_map und array_filter zu verstehen.

Die Funktion array_reduce nimmt ein Array, eine Funktion mit zwei Argumenten und einen 'Akkumulator', wie folgt:

array_reduce(array('a', 'b', 'c', 'd'),
             'my_function',
             $accumulator)

Die Elemente des Arrays werden nacheinander mit dem Akkumulator kombiniert, wobei die angegebene Funktion verwendet wird. Das Ergebnis des obigen Aufrufs ist dasselbe wie bei dieser Funktion:

my_function(
  my_function(
    my_function(
      my_function(
        $accumulator,
        'a'),
      'b'),
    'c'),
  'd')

Wenn Sie es vorziehen, in Form von Schleifen zu denken, ist es so, als ob Sie folgendes tun würden (ich habe dies tatsächlich als Ausweichlösung verwendet, wenn array_reduce nicht verfügbar war):

function array_reduce($array, $function, $accumulator) {
  foreach ($array as $element) {
    $accumulator = $function($accumulator, $element);
  }
  return $accumulator;
}

Diese Schleifenversion macht deutlich, warum ich das dritte Argument als "Akkumulator" bezeichnet habe: Wir können es verwenden, um die Ergebnisse in jeder Iteration zu akkumulieren.

Was hat das nun mit array_map und array_filter zu tun? Es stellt sich heraus, dass sie beide eine besondere Art von array_reduce sind. Wir können sie wie folgt implementieren:

array_map($function, $array)    === array_reduce($array, $MAP,    array())
array_filter($array, $function) === array_reduce($array, $FILTER, array())

Ignorieren Sie die Tatsache, dass array_map und array_filter ihre Argumente in einer anderen Reihenfolge annehmen; das ist nur eine weitere Eigenart von PHP. Wichtig ist, dass die rechte Seite bis auf die Funktionen, die ich $MAP und $FILTER genannt habe, identisch ist. Wie sehen sie also aus?

$MAP = function($accumulator, $element) {
  $accumulator[] = $function($element);
  return $accumulator;
};

$FILTER = function($accumulator, $element) {
  if ($function($element)) $accumulator[] = $element;
  return $accumulator;
};

Wie Sie sehen können, nehmen beide Funktionen den $Akkumulator auf und geben ihn wieder zurück. Es gibt zwei Unterschiede in diesen Funktionen:

  • $MAP wird immer an $accumulator angehängt, aber $FILTER tut dies nur, wenn $function($element) TRUE ist.
  • $FILTER hängt das ursprüngliche Element an, aber $MAP hängt $function($element) an.

Beachten Sie, dass es sich hierbei keineswegs um nutzlose Belanglosigkeiten handelt; wir können sie nutzen, um unsere Algorithmen effizienter zu machen!

Wir können oft Code wie diese beiden Beispiele sehen:

// Transform the valid inputs
array_map('transform', array_filter($inputs, 'valid'))

// Get all numeric IDs
array_filter(array_map('get_id', $inputs), 'is_numeric')

Durch die Verwendung von array_map und array_filter anstelle von Schleifen sehen diese Beispiele sehr schön aus. Es kann jedoch sehr ineffizient sein, wenn $inputs groß ist, da der erste Aufruf (map oder filter) $inputs durchläuft und ein Zwischenarray erstellt. Dieses Zwischen-Array wird direkt an den zweiten Aufruf weitergegeben, der das Ganze noch einmal durchläuft, und dann muss das Zwischen-Array entsorgt werden.

Wir können dieses Zwischenfeld loswerden, indem wir die Tatsache ausnutzen, dass array_map und array_filter beide Beispiele für array_reduce sind. Wenn wir sie kombinieren, müssen wir $inputs in jedem Beispiel nur einmal durchlaufen:

// 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())

HINWEIS: Meine obigen Implementierungen von array_map und array_filter verhalten sich nicht genau wie die von PHP, da meine array_map nur ein Array auf einmal verarbeiten kann und mein array_filter nicht "empty" als Standardfunktion verwendet. Außerdem werden beide keine Schlüssel beibehalten.

Es ist nicht schwer, sie so zu gestalten, dass sie sich wie PHPs verhalten, aber ich hatte das Gefühl, dass diese Komplikationen die Kernidee schwerer erkennbar machen würden.

1voto

slevy1 Punkte 3689

Die folgende Überarbeitung versucht, PHPs array_filer(), array_map() und array_walk(), die alle aus der funktionalen Programmierung stammen, klarer abzugrenzen:

array_filter() filtert Daten heraus und erzeugt als Ergebnis ein neues Array, das nur die gewünschten Elemente des früheren Arrays enthält, wie folgt:

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

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

Live-Code aquí

Alle numerischen Werte werden aus $array herausgefiltert, so dass $filtered nur noch Fruchtarten enthält.

array_map() erstellt ebenfalls ein neues Array, aber im Gegensatz zu array_filter() enthält das resultierende Array jede Element der Eingabe $filtered, jedoch mit geänderten Werten, da auf jedes Element ein Callback angewendet wird, wie folgt:

<?php

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

Live-Code aquí

Der Code in diesem Fall wendet einen Rückruf unter Verwendung der eingebauten Funktion strtoupper() an, aber auch eine benutzerdefinierte Funktion ist eine praktikable Option. Der Rückruf gilt für jedes Element von $filtered und erzeugt dadurch $nu, dessen Elemente Werte in Großbuchstaben enthalten.

Im nächsten Schnipsel durchläuft array walk() $nu und ändert jedes Element gegenüber dem Referenzoperator '&'. Die Änderungen erfolgen, ohne ein zusätzliches Array zu erzeugen. Der Wert jedes Elements wird stattdessen in eine informativere Zeichenkette geändert, die den Schlüssel, die Kategorie und den Wert angibt.

<?php

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

Voir Demo

Hinweis: Die Callback-Funktion in Bezug auf array_walk() benötigt zwei Parameter, die automatisch den Wert und den Schlüssel eines Elements in dieser Reihenfolge ermitteln, wenn sie von array_walk() aufgerufen wird. (Siehe mehr aquí ).

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X