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.