正確にどのようなことの間の差であるarray_map
、array_walk
とarray_filter
。ドキュメントからわかるのは、コールバック関数を渡して、提供された配列に対してアクションを実行できることです。しかし、私はそれらの間の特定の違いを見つけるようには見えません。
彼らは同じことをしますか?
それらは交換可能に使用できますか?
実例が少しでも違う場合は、参考にしていただければ幸いです。
正確にどのようなことの間の差であるarray_map
、array_walk
とarray_filter
。ドキュメントからわかるのは、コールバック関数を渡して、提供された配列に対してアクションを実行できることです。しかし、私はそれらの間の特定の違いを見つけるようには見えません。
彼らは同じことをしますか?
それらは交換可能に使用できますか?
実例が少しでも違う場合は、参考にしていただければ幸いです。
回答:
array_map
入力配列内の値を変更することはできませんarray_walk
。特に、array_map
その引数を変更することはありません。array_map
配列キーでは操作できませんarray_walk
。array_map
新しい配列をarray_walk
返し、のみを返しますtrue
。したがって、1つの配列をトラバースした結果として配列を作成したくない場合は、を使用する必要がありますarray_walk
。array_map
また、任意の数の配列を受け取ることができarray_walk
、1つだけで動作しながら、それらを並列に反復できます。array_walk
コールバックに渡す追加の任意のパラメータを受け取ることができます。これは、PHP 5.3(匿名関数が導入されたとき)以降はほとんど関係ありません。array_map
長さは、最大の入力配列と同じです。array_walk
配列は返しませんが、同時に元の配列の要素数を変更することはできません。array_filter
フィルタリング関数に従って、配列の要素のサブセットのみを選択します。キーは保持されます。例:
<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>
結果:
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
)
array_map(callback($key, $value), array_keys($array), $array)
関数をデータの配列にマッピングするアイデアは、関数型プログラミングに由来します。あなたが考えるべきではないarray_map
としてforeach
、配列の各要素に関数を呼び出すループ(それはだにもかかわらず、それが実装されていますか)。これは、関数を配列内の各要素に個別に適用することと考える必要があります。
理論的には、データに適用される関数はデータにのみ影響し、グローバル状態には影響しないため、関数マッピングなどの処理は並行して行うことができます。これは、array_map
が関数を適用する順序を選択できるためです(PHPではそうではありませんが)。
array_walk
一方、それはデータの配列を処理するための正反対のアプローチです。各アイテムを個別に処理する代わりに、状態(&$userdata
)を使用し、(foreachループのように)アイテムを適切に編集できます。アイテムが$funcname
適用されるたびに、プログラムのグローバル状態が変更される可能性があるため、アイテムを処理するための単一の正しい方法が必要です。
戻るPHPの土地で、array_map
かつarray_walk
除いてほとんど同じですarray_walk
あなたのデータの反復をより詳細に制御できますし、通常は新しい「変更」配列を返すVSインプレース「チェンジ」のデータをするために使用されます。
array_filter
は本当にarray_walk
(またはarray_reduce
)のアプリケーションであり、多かれ少なかれ便宜上提供されています。
array_filter()
を使用してどのように実装できるか説明できますarray_walk()
か?
ドキュメントから、
bool array_walk(array&$ array、callback $ funcname [、mixed $ userdata])<-return bool
array_walkは、配列と関数F
を取り、すべての要素xをで置き換えることにより、それを変更しF(x)
ます。
array array_map(callback $ callback、array $ arr1 [、array $ ...])<-return array
array_mapは、インプレースで変更する代わりに、変換された要素を含む新しい配列を返すことを除いて、まったく同じことを行います。
array array_filter(array $ input [、callback $ callback])<-return array
F
要素を変換する代わりに、functionを指定したarray_filterF(x)
は、trueでない要素を削除します
array_walk
ような配列が返されると想定しarray_map
、問題は自分の関数にあると考えました。これを見て初めて、戻り値の型がブール型であることを理解しました。
他の回答は、array_walk(インプレース変更)とarray_map(変更されたコピーを返す)の違いをよく示しています。ただし、array_reduceについては実際には触れていません。これは、array_mapとarray_filterを理解するためのわかりやすい方法です。
array_reduce関数は、次のように、配列、2つの引数を持つ関数、および「アキュムレータ」を受け取ります。
array_reduce(array('a', 'b', 'c', 'd'),
'my_function',
$accumulator)
配列の要素は、指定された関数を使用して、一度に1つずつアキュムレータと結合されます。上記の呼び出しの結果は、これを実行した場合と同じです。
my_function(
my_function(
my_function(
my_function(
$accumulator,
'a'),
'b'),
'c'),
'd')
ループの観点から考えると、次のようになります(実際には、array_reduceが使用できない場合のフォールバックとしてこれを使用しました)。
function array_reduce($array, $function, $accumulator) {
foreach ($array as $element) {
$accumulator = $function($accumulator, $element);
}
return $accumulator;
}
このループバージョンでは、3番目の引数を「アキュムレータ」と呼んだ理由が明らかになります。これを使用して、各反復を通じて結果を累積できます。
それで、これはarray_mapとarray_filterとどう関係しているのでしょうか?どちらも特定の種類のarray_reduceであることがわかります。次のように実装できます。
array_map($function, $array) === array_reduce($array, $MAP, array())
array_filter($array, $function) === array_reduce($array, $FILTER, array())
array_mapとarray_filterは引数を別の順序で受け取るという事実を無視します。これは、PHPのもう1つの癖です。重要な点は、$ MAPと$ FILTERを呼び出した関数を除いて、右側は同じであることです。それで、彼らはどのように見えますか?
$MAP = function($accumulator, $element) {
$accumulator[] = $function($element);
return $accumulator;
};
$FILTER = function($accumulator, $element) {
if ($function($element)) $accumulator[] = $element;
return $accumulator;
};
ご覧のとおり、どちらの関数も$ accumulatorを受け取り、それを再び返します。これらの関数には2つの違いがあります。
これは役に立たない雑学にはほど遠いことに注意してください。それを使用して、アルゴリズムをより効率的にすることができます!
次の2つの例のようなコードがよく見られます。
// Transform the valid inputs
array_map('transform', array_filter($inputs, 'valid'))
// Get all numeric IDs
array_filter(array_map('get_id', $inputs), 'is_numeric')
ループの代わりにarray_mapとarray_filterを使用すると、これらの例は見栄えがよくなります。ただし、最初の呼び出し(マップまたはフィルター)が$ inputsをトラバースして中間配列を構築するため、$ inputsが大きい場合は非常に非効率的です。この中間配列は、2番目の呼び出しに直接渡されます。2番目の呼び出しは、もう一度全体をトラバースします。次に、中間配列をガベージコレクションする必要があります。
array_mapとarray_filterがどちらもarray_reduceの例であることを利用して、この中間配列を取り除くことができます。それらを組み合わせると、各例で$ inputsを1回トラバースするだけで済みます。
// 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())
注:上記のarray_mapとarray_filterの実装は、PHPとまったく同じように動作しません。これは、array_mapが一度に1つの配列しか処理できず、array_filterがデフォルトの$関数として「空」を使用しないためです。また、どちらもキーを保持しません。
それらをPHPのように動作させることは難しくありませんが、これらの複雑さが原因でコアアイデアを見つけるのが難しくなると感じました。
次の改訂では、PHPのarray_filer()、array_map()、およびarray_walk()をより明確に示しています。これらはすべて関数型プログラミングに由来しています。
array_filter()はデータをフィルターにかけ、結果として次のように、以前の配列の必要な項目のみを保持する新しい配列を生成します。
<?php
$array = array(1, "apples",2, "oranges",3, "plums");
$filtered = array_filter( $array, "ctype_alpha");
var_dump($filtered);
?>
ここにライブコード
すべての数値は$ arrayからフィルターで除外され、$ filteredは果物のタイプのみで残ります。
array_map()も新しい配列を作成しますが、array_filter()とは異なり、結果の配列には、入力$ filteredのすべての要素が含まれますが、次のように各要素にコールバックを適用するため、値が変更されています。
<?php
$nu = array_map( "strtoupper", $filtered);
var_dump($nu);
?>
ここにライブコード
この場合のコードは、組み込みのstrtoupper()を使用してコールバックを適用しますが、ユーザー定義関数も別の実行可能なオプションです。コールバックは$ filteredのすべてのアイテムに適用されるため、要素に大文字の値が含まれる$ nuが生成されます。
次のスニペットでは、配列walk()が$ nuをたどり、参照演算子 '&'に対して各要素に変更を加えます。追加のアレイを作成せずに変更が行われます。すべての要素の値は、そのキー、カテゴリ、および値を指定するより有益な文字列に変わります。
<?php
$f = function(&$item,$key,$prefix) {
$item = "$key: $prefix: $item";
};
array_walk($nu, $f,"fruit");
var_dump($nu);
?>
デモを見る
注:array_walk()に関するコールバック関数は、array_walk()によって呼び出された場合にも、要素の値とそのキーをこの順序で自動的に取得する2つのパラメーターを取ります。(詳細はこちら)。
$lambda
と$callback
は既存の関数のeta-expansionであり、完全に冗長であることに注意してください。基礎となる関数(の名前)を渡すことで同じ結果を得ることができます:$filtered = array_filter($array, 'ctype_alpha');
および$nu = array_map('strtoupper', $filtered);