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.