Array_map, array_walk ve array_filter arasındaki fark


373

Tam olarak ne arasındaki farktır array_map, array_walkve array_filter. Belgelerden görebildiğim şey, verilen dizi üzerinde bir eylem gerçekleştirmek için bir geri arama işlevi geçirebilmenizdir. Ama aralarında belirli bir fark bulamıyorum.

Aynı şeyi yapıyorlar mı?
Bunlar birbirinin yerine kullanılabilir mi?

Hiç farklı olsaydı, açıklayıcı örnekle ilgili yardımınızı takdir ediyorum.


Bu, array_reduce () aracılığıyla adlandırılmış dizi işleme için harika bir numaradır. Array_map, array_walk ve array_filter'ı araştırıyorsanız okunmaya değer. stackoverflow.com/questions/11563119/…
Lance Cleveland

Yanıtlar:


564
  • Değerleri Değiştirme:
    • array_mapcan ise giriş dizisi / dizileri içindeki değerleri değiştiremez array_walk; özellikle array_mapargümanlarını asla değiştirmez.
  • Dizi Anahtarlarına Erişim:
  • Geri dönüş değeri:
    • array_mapyeni bir dizi array_walkdöndürür , yalnızca döndürür true. Bu nedenle, bir diziyi geçmenin bir sonucu olarak bir dizi oluşturmak istemiyorsanız, kullanmalısınız array_walk.
  • Çoklu Dizileri Yineleme:
    • array_mapayrıca isteğe bağlı sayıda dizi alabilir ve bunlara paralel olarak yineleyebilir, array_walkyalnızca bir dizide çalışır.
  • Rasgele Verilerin Geri Aramaya Geçirilmesi:
    • array_walkgeri aramaya geçmek için fazladan isteğe bağlı bir parametre alabilir. PHP 5.3'ten beri bu çoğunlukla önemsizdir ( anonim işlevler sunulduğunda).
  • Döndürülen Dizinin Uzunluğu:
    • Sonuçta elde edilen dizi, array_mapen büyük girdi dizisiyle aynı uzunluğa sahiptir; array_walkbir dizi döndürmez, ancak aynı zamanda orijinal dizinin öğe sayısını değiştiremez; array_filterfiltreleme işlevine göre dizinin öğelerinin yalnızca bir alt kümesini seçer. Anahtarları korur.

Misal:

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

Sonuç:

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
)

3
PHP el kitabı şöyle der: "array_walk (): Yalnızca dizinin değerleri değişebilir;"
feeela

10
"array_map dizi anahtarlarıyla çalışamaz" bu doğru değildir:array_map(callback($key, $value), array_keys($array), $array)
Jarek Jakubowski

12
Hala herhangi bir dizinin anahtarlarına erişmiyor, anahtarlardan oluşturduğunuz bir diziye koyduğunuz değerlere erişiyor. Bu geçici bir çözümdür, ifadeyi reddetmez.
inarilo

array_map değerleri örtük olarak değiştirmezken, sonucu aynı diziye atayarak temelde değiştirir ve aynı dizide çalışan 'paradoksal olarak' array_walk, referans (dizi) değerine geçmedikçe doğrudan değerlerini değiştirmez walk, dizinleri / öğeleri, anonim işlev kullanım yoluyla dolaylı olarak orijinal diziyi geçen deyimden kaldırabilir, ancak geçici bir çözümdür). Sonuç olarak, değerlerin değiştirilmesi ya da bir değerin referansla döndürülmesi ya da iletilmesi daha az fark yaratıyorsa, ancak dizi yürüyüşü, dizinlerle ve çoklu dizilere sahip dizi haritasıyla çalışır
FantomX1

Ayrıca, dizi yürüyüşünün ilk dizi parametresini referans olarak
alması fark etmeksizin

91

Bir işlevi veri dizisine eşleme fikri işlevsel programlamadan gelir. Dizinin her öğesinde bir işlevi çağıran array_mapbir foreachdöngü olarak düşünmemelisiniz (bu şekilde uygulanmış olsa da). Dizideki her öğeye işlevi bağımsız olarak uyguladığı düşünülmelidir.

Teoride fonksiyon haritalama gibi şeyler paralel olarak yapılabilir çünkü verilere uygulanan fonksiyon SADECE küresel durumu DEĞİL, verileri etkilemelidir. Bunun nedeni, bir array_mapfonksiyonun öğelerdeki öğeye uygulanacağı herhangi bir sırayı seçebilmesidir (PHP'de olmasa bile).

array_walkÖte yandan, veri dizilerinin işlenmesinde tam tersi bir yaklaşımdır. Her öğeyi ayrı ayrı işlemek yerine, bir state ( &$userdata) kullanır ve öğeyi yerinde düzenleyebilir (foreach döngüsü gibi). Bir öğe her $funcnameuygulandığında, programın genel durumunu değiştirebilir ve bu nedenle öğeleri işlemenin tek bir doğru yolunu gerektirir .

Geri PHP arazi array_mapve array_walkneredeyse aynı array_walközledim size veri yineleme üzerinde daha fazla kontrol verir ve normalde yeni bir "değiştirilmiş" dizi döndürme vs yerinde veri "değiştirmek" için kullanılır.

array_filtergerçekten array_walk(veya array_reduce) bir uygulamadır ve az ya da çok kolaylık sağlamak için verilmiştir.


5
"Paragrafta fonksiyon eşleme gibi şeyler paralel olarak yapılabilir, çünkü verilere uygulanan fonksiyon SADECE küresel durumu DEĞİL, verileri etkilemelidir." Bizim için paralel programcılar, bu akılda tutulması gereken yararlı bir şey.
etherice

array_filter()Kullanarak nasıl uygulanabileceğini açıklayabilir misiniz array_walk()?
pfrenssen

40

Belgelerden,

bool array_walk (dizi & $ dizi, geri arama $ funcname [, mixed $ userdata]) <-return bool

array_walk bir dizi ve işlev alır Fve her x öğesini değiştirerek onu değiştirir F(x).

dizi array_map (geri arama $ geri arama, dizi $ arr1 [, dizi $ ...]) <- dönüş dizisi

array_map , yerinde değişiklik yapmak yerine dönüştürülen öğelerle yeni bir dizi döndürmesi dışında tam olarak aynı şeyi yapar .

dizi array_filter (dizi $ girişi [, geri arama $ geri arama]) <- dönüş dizisi

array_filter işlevi F, öğeleri dönüştürmek yerine, F(x)doğru olmayan öğeleri kaldırır


Dizi değerlerimin neden kaybolduğunu anlayamadım. Belgelere baktığımda array_walkbenzer bir dizi döndürdüğümü array_mapve sorunun benim fonksiyonumda olduğunu düşündüm. Ben dönüş türü boolean olduğunu görene kadar fark etmedi.
Dylan Valade

22

Diğer cevaplar, dizi_yüzü (yerinde değişiklik) ve dizi_map (değiştirilmiş kopyayı döndür) arasındaki farkı oldukça iyi göstermektedir. Ancak, array_map ve array_filter'ı anlamanın aydınlatıcı bir yolu olan array_reduce'dan gerçekten bahsetmezler.

Array_reduce işlevi bir dizi, iki bağımsız değişken işlevi ve bir 'akümülatör' alır, şöyle:

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

Dizinin elemanları, verilen işlev kullanılarak birer birer akümülatörle birleştirilir. Yukarıdaki çağrının sonucu bunu yapmakla aynıdır:

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

Döngüler açısından düşünmeyi tercih ediyorsanız, aşağıdakileri yapmak gibi bir şeydir (array_reduce kullanılamadığında bunu bir yedek olarak kullandım):

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

Bu döngüsel versiyon, üçüncü argümanı neden 'akümülatör' olarak adlandırdığımı açıklığa kavuşturuyor: bunu her bir yineleme yoluyla sonuçları biriktirmek için kullanabiliriz.

Peki bunun array_map ve array_filter ile ne ilgisi var? Her ikisinin de belirli bir dizi_açıklama olduğu ortaya çıkıyor. Bunları şu şekilde uygulayabiliriz:

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

Array_map ve array_filter değişkenlerinin argümanlarını farklı bir sırayla aldıklarını dikkate almayın; PHP'nin başka bir tuhaflığı. Önemli olan, sağ tarafın $ MAP ve $ FILTER olarak adlandırdığım işlevler dışında aynı olmasıdır. Peki, neye benziyorlar?

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

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

Gördüğünüz gibi, her iki fonksiyon da $ akümülatörünü alıp tekrar geri veriyor. Bu işlevlerde iki fark vardır:

  • $ MAP her zaman $ biriktiricisine eklenir, ancak $ FILTER bunu yalnızca $ işlevi ($ element) TRUE ise yapar.
  • $ FILTER orijinal öğeyi ekler, ancak $ MAP $ işlevini ($ element) ekler.

Bunun işe yaramaz önemsiz şeylerden uzak olduğunu unutmayın; algoritmalarımızı daha verimli hale getirmek için kullanabiliriz!

Bu iki örnek gibi kodu sık sık görebiliriz:

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

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

Döngüler yerine array_map ve array_filter kullanmak bu örneklerin oldukça güzel görünmesini sağlar. Bununla birlikte, ilk çağrı (harita veya filtre) $ girişlerini geçip bir ara dizi oluşturacağından $ girişlerinin büyük olması çok verimsiz olabilir. Bu ara dizi, her şeyi tekrar geçecek olan ikinci aramaya doğrudan geçirilir, daha sonra ara dizinin çöp toplanması gerekir.

Bu ara diziden, array_map ve array_filter öğelerinin array_reduce örneklerinden yararlanarak kurtulabiliriz. Bunları birleştirerek, her örnekte yalnızca bir kez $ girdisini geçmeliyiz:

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

NOT: Yukarıdaki array_map ve array_filter uygulamalarım PHP gibi davranmayacaktır, çünkü array_map her seferinde yalnızca bir dizi işleyebilir ve array_filter varsayılan $ işlevi olarak "empty" kullanmaz. Ayrıca, anahtarları da korumaz.

Onları PHP gibi davranmak zor değil, ama bu komplikasyonların temel fikri fark etmesini zorlaştıracağını hissettim.


1

Aşağıdaki düzeltme, tümü işlevsel programlamadan kaynaklanan PHP'nin array_filer (), array_map () ve array_walk () yöntemlerini daha net bir şekilde tanımlamayı amaçlamaktadır:

array_filter () verileri filtreler ve sonuç olarak aşağıdaki gibi yalnızca eski dizinin istenen öğelerini tutan yeni bir dizi üretir:

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

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

burada canlı kod

Tüm sayısal değerler $ dizisinden filtrelenir, $ sadece meyve türleriyle filtrelenir.

array_map () da yeni bir dizi oluşturur, ancak array_filter () 'den farklı olarak, sonuçta elde edilen dizi, her bir öğeye geri çağrı uygulayarak, filtrelenen girişin her öğesini $ filtre uygular, ancak değiştirilmiş değerlerle içerir:

<?php

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

burada canlı kod

Bu durumda kod, yerleşik strtoupper () kullanarak bir geri arama uygular, ancak kullanıcı tanımlı bir işlev de başka bir geçerli seçenektir. Geri arama, filtrelenen $ öğesinin her bir öğesi için geçerlidir ve böylece öğeleri büyük harf değerleri içeren $ nu oluşturur.

Sonraki snippet'te dizi walk (), $ nu değerini geçer ve '&' referans operatörüne göre her öğede değişiklik yapar. Değişiklikler ek bir dizi oluşturmadan gerçekleşir. Her öğenin değeri, anahtarını, kategorisini ve değerini belirten daha bilgilendirici bir dizeye dönüşür.

<?php

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

Bkz demo

Not: array_walk () ile ilgili geri çağırma işlevi, bir elemanın değerini ve anahtarını otomatik olarak ve array_walk () tarafından çağrıldığında da bu sırayla alacak iki parametre alır. (Daha fazlasını burada görebilirsiniz ).


1
Fonksiyonların $lambdave $callbacksadece mevcut fonksiyonların eta-genişlemeleri olduğunu ve bu nedenle tamamen gereksiz olduğunu unutmayın. Altta yatan işlevi geçerek (adını) aynı sonucu elde edebilirsiniz: $filtered = array_filter($array, 'ctype_alpha');ve$nu = array_map('strtoupper', $filtered);
Warbo
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.