Różnica między mapą tablicy, ścieżką tablicy i filtrem tablicy

Jaka jest dokładnie różnica między array_map, array_walk i array_filter. Co mogłem zobaczyć z dokumentacji jest to, że można przekazać funkcję zwrotną do wykonania akcji na dostarczonej tablicy. Ale nie widzę między nimi żadnej różnicy.

Czy wykonują to samo?
Czy można je stosować zamiennie? Byłabym wdzięczna za pomoc przy ilustracyjnym przykładzie, jeśli w ogóle są inne.
Author: Gras Double, 2010-08-08

5 answers

  • Zmiana Wartości:
    • array_map nie można zmienić wartości wewnątrz tablic wejściowych, podczas gdy array_walk can; w szczególności, array_map nigdy nie zmienia swoich argumentów.
  • Dostęp Do Kluczy Tablicy:
  • Return Value:
    • array_map zwraca nową tablicę, array_walk tylko Zwroty true/false. Stąd, jeśli nie chcesz utworzyć tablicę w wyniku przejścia jednej tablicy, powinieneś użyć array_walk.
  • Iteracja Wielu Tablic:
    • array_map również może odbierać dowolną liczbę tablic i może nad nimi iterować równolegle, podczas gdy array_walk działa tylko na jednym.
  • przekazywanie dowolnych danych do wywołania zwrotnego:
    • array_walk może otrzymać dodatkowy dowolny parametr do przekazania do wywołania zwrotnego. To głównie nieistotne od PHP 5.3 (kiedy funkcje anonimowe zostały wprowadzone).
  • Długość zwracanej tablicy:
    • tablica wynikowa array_map ma taką samą długość jak największa tablica wejściowa; array_walk nie zwraca tablicy, ale jednocześnie nie może zmienić liczby elementów tablicy oryginalnej; array_filter wybiera tylko podzbiór elementów tablicy zgodnie z funkcją filtrowania. Zachowuje klucze.

Przykład:

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

Wynik:

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
Author: Artefacto,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-07-06 20:35:07

Idea mapowania funkcji do tablicy danych pochodzi z programowania funkcyjnego. Nie powinieneś myśleć o array_map jako o pętli foreach, która wywołuje funkcję na każdym elemencie tablicy (nawet jeśli tak jest zaimplementowana). Należy traktować to jako zastosowanie funkcji do każdego elementu w tablicy niezależnie.

Teoretycznie takie rzeczy jak mapowanie funkcji mogą być wykonywane równolegle, ponieważ funkcja stosowana do danych powinna wpływać tylko na dane, a nie Państwo globalne. To dlatego, że array_map może wybrać dowolną kolejność, w jakiej ma być zastosowana funkcja do elementów w (nawet jeśli w PHP tak nie jest).

array_walk z drugiej strony jest to dokładnie odwrotne podejście do obsługi tablic danych. Zamiast obsługiwać każdy element oddzielnie, używa stanu (&$userdata) i może edytować element w miejscu (podobnie jak pętla foreach). Ponieważ za każdym razem, gdy element ma $funcname zastosowany do niego, może zmienić globalny stan programu i do tego wymaga jednego poprawny Sposób przetwarzania przedmiotów.

W PHP land, array_map i array_walk są prawie identyczne z tym, że array_walk daje większą kontrolę nad iteracją danych i jest zwykle używany do "zmiany" danych w miejscu zamiast zwracania nowej "zmienionej" tablicy.

array_filter jest to naprawdę aplikacja array_walk (lub array_reduce) i to mniej więcej tylko dla wygody.

 85
Author: Kendall Hopkins,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-06-18 08:45:11

Z dokumentacji,

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

Array_walk pobiera tablicę i funkcję F i modyfikuje ją, zamieniając każdy element x na F(x).

Array_map (callback $callback , array $arr1 [, array $... ])

Array_map robi dokładnie to samo z wyjątkiem , że zamiast modyfikować w miejscu zwróci nową tablicę z przekształconymi elementami.

Array array_filter ( array $input [, callback $callback ])

Array_filter z funkcją F, zamiast przekształcać elementy, usunie wszystkie elementy, dla których F(x) nie jest prawdą

 36
Author: Steven Schlansker,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2011-06-01 13:20:13

Inne odpowiedzi pokazują różnicę między array_walk (modyfikacja in-place) i array_map (return modified copy) całkiem dobrze. Jednak tak naprawdę nie wspominają o array_reduce, co jest pouczającym sposobem na zrozumienie array_map i array_filter.

Funkcja array_reduce pobiera tablicę, funkcję dwuargumentową i 'akumulator', tak:

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

Elementy tablicy są łączone z akumulatorem pojedynczo, używając podanej funkcji. Wynik powyższe wywołanie jest takie samo jak to:

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

Jeśli wolisz myśleć w kategoriach pętli, to tak, jakby to zrobić (użyłem tego jako alternatywy, gdy array_reduce nie było dostępne):

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

Ta wersja pętli wyjaśnia, dlaczego nazwałem trzeci argument "akumulatorem": możemy go użyć do gromadzenia wyników przez każdą iterację.

Więc co to ma wspólnego z array_map i array_filter? Okazuje się, że oboje są szczególnym rodzaj array_reduce. Możemy je zaimplementować w następujący sposób:

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

Ignoruj fakt, że array_map i array_filter przyjmują swoje argumenty w innej kolejności; to po prostu kolejny dziwak PHP. Ważne jest to, że prawa strona jest identyczna z wyjątkiem funkcji, które nazwałem $MAP i $ FILTER. Jak wyglądają?

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

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

Jak widzisz, obie funkcje pobierają $accumulator i zwracają go ponownie. Istnieją dwie różnice w tych funkcje:

  • $ MAP będzie zawsze dołączana do $ accumulator, ale $FILTER zrobi to tylko wtedy, gdy$function ($element) jest prawdziwe.
  • $FILTER dodaje oryginalny element, ale $MAP dodaje $ function ($element).

Zauważ, że nie jest to bezużyteczna ciekawostka; możemy jej użyć, aby nasze algorytmy były bardziej wydajne!

Często widzimy kod podobny do tych dwóch przykładów:

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

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

Używanie array_map i array_filter zamiast pętli sprawia, że te przykłady wyglądają całkiem ładnie. Jednakże, może to być bardzo nieefektywne, jeśli $Input jest duży, ponieważ pierwsze wywołanie (map lub filter) przemierzy $Input i zbuduje tablicę pośrednią. Ta tablica pośrednia jest przekazywana bezpośrednio do drugiego wywołania, które ponownie przejedzie całość, wtedy tablica pośrednia będzie musiała zostać usunięta.

Możemy pozbyć się tej pośredniej tablicy, wykorzystując fakt, że array_map i array_filter są przykładami array_reduce. Łącząc je, musimy tylko przesuń $wejścia raz w każdym przykładzie:

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

UWAGA: moje implementacje array_map i array_filter nie będą zachowywać się dokładnie tak jak PHP, ponieważ moja array_map może obsługiwać tylko jedną tablicę na raz, a mój array_filter nie będzie używał "empty" jako domyślnej funkcji$. Również klucze nie będą zachowywane.

Nie jest trudno sprawić, aby zachowywały się jak PHP, ale czułem, że te komplikacje sprawią, że główny pomysł będzie trudniejszy do zauważenia.

 16
Author: Warbo,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2014-05-01 17:51:07

Następująca zmiana ma na celu wyraźniejsze zdefiniowanie array_filer(), array_map () i array_walk (), z których wszystkie pochodzą z programowania funkcyjnego:

Array_filter() filtruje dane, tworząc w rezultacie nową tablicę zawierającą tylko pożądane pozycje poprzedniej tablicy, w następujący sposób:

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

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

Live code here

Wszystkie wartości liczbowe są filtrowane z tablicy$, pozostawiając $filtrowane tylko z typami owoców.

Array_map () tworzy również nowy tablica, ale w przeciwieństwie do array_filter() tablica wynikowa zawiera każdy element wejściowy $filtered, ale ze zmienionymi wartościami, z powodu zastosowania wywołania zwrotnego do każdego elementu, w następujący sposób:

<?php

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

Live code here

Kod w tym przypadku stosuje wywołanie zwrotne przy użyciu wbudowanej strtoupper (), ale funkcja zdefiniowana przez użytkownika jest również inną realną opcją. Wywołanie zwrotne odnosi się do każdego elementu $filtered i tym samym powoduje $nu, którego elementy zawierają wielkie litery wartości.

W następnym fragmencie, array walk() przemierza $nu i wprowadza zmiany do każdego elementu vis a vis operatora referencyjnego'&'. Zmiany zachodzą bez tworzenia dodatkowej tablicy. Wartość każdego elementu zmienia się na bardziej pouczający łańcuch określający jego klucz, kategorię i wartość.

<?php

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

Zobacz demo

Uwaga: funkcja wywołania zwrotnego w odniesieniu do array_walk() pobiera dwa parametry, które automatycznie pobierają wartość elementu i jego klucz i w tej kolejności również, gdy jest wywoływana przez array_walk (). (Zobacz więcej tutaj ).

 1
Author: slevy1,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-05-23 20:39:01