概要
Collection
には引数にコールバックをとるメソッドが準備されている。これらはコレクションの各要素にコールバックで定義された処理をし、その結果に応じて要素の絞り込み、各要素への処理の適用、各要素を用いた縮退処理を行う。
いずれも元のコレクションは変更されず、戻り値として新たなコレクションやオブジェクト、変数などが返される。
単純配列型に対するメソッド
filter()~条件に合う要素の絞り込み
filter()
は、設定した条件により元のコレクションの要素の一部を取り出す。
filter()
のコールバックは、各要素に対応する引数を1つ撮る- コールバックの戻り値は、受け取った要素に対する条件の評価結果(
true
/false
) filter()
の戻り値として、元のコレクションのうち条件に合致する要素だけが残ったコレクションが返される
1 |
$collection->filter(function($element) { return $elementの抽出条件; }); |
以下の例は、奇数要素のみを取り出す例。
1 2 3 4 5 6 7 |
$collection = collect([1, 2, 3, 4, 5]); $filtered = $collection->filter(function($element) { return $element % 2 == 1; }); dd($filtered); |
基数要素だけが残ったコレクションが得られる。
1 2 3 4 5 6 7 |
Illuminate\Support\Collection {#1274 ▼ #items: array:3 [▼ 0 => 1 2 => 3 4 => 5 ] } |
以下は4未満の要素のみを残す例。
1 2 3 |
$filtered = $collection->filter(function($element) { return $element < 4; }); |
4未満の要素のみが残っている。
1 2 3 4 5 6 7 |
Illuminate\Support\Collection {#1274 ▼ #items: array:3 [▼ 0 => 1 1 => 2 2 => 3 ] } |
reject()~条件に合わない要素の絞り込み
reject()
はfilter()
の逆で、条件に合う要素を取り除いた残りのコレクションを返す。
1 |
$collection->reject(function($element) { return $elementの除外条件; }); |
以下は奇数要素のみを取り除く例。
1 2 3 |
$rejected = $collection->filter(function($element) { return $element % 2 == 1; }); |
奇数要素が除かれ、偶数要素のみが残っている。
1 2 3 4 5 6 |
Illuminate\Support\Collection {#1271 ▼ #items: array:2 [▼ 1 => 2 3 => 4 ] } |
map()~各要素への処理のマッピング
map()
は設定した処理を元のコレクションの全要素に適用する。
map()
のコールバックは、各要素に対応する引数を1つ撮る- コールバックの戻り値は、処理の結果更新される各要素の値
map()
の戻り値として、元のコレクションの各要素にコールバックの処理が適用されたコレクションが返される
1 |
$collection->map(function($element) { return 加工後の$element; }); |
以下はコレクションの各要素を10倍する例。
1 2 3 4 5 6 7 |
$collection = collect([1, 2, 3, 4, 5]); $mapped = $collection->map(function($element) { return $element * 10; }); dd($mapped); |
元の要素が10倍された結果になっている。
1 2 3 4 5 6 7 8 9 |
Illuminate\Support\Collection {#1271 ▼ #items: array:5 [▼ 0 => 10 1 => 20 2 => 30 3 => 40 4 => 50 ] } |
reduce()~縮退処理
ここでいう縮退とは、各要素やその加工結果を1つの結果にまとめ込んでいくものとする。
例として「コレクションの各要素の値の合計を求める」という処理の場合、「合計値」という結果に要素ごとの値を「足し込む」という処理になる。
このためreuce()
はfilter()
やmap()
と以下の2点で異なる。
- コールバックの引数は縮退の途中結果とその時点での要素の2つの引数をとる
reduce()
自身が上記のコールバックと縮退処理の初期値の2つの引数をとる
コールバックについては以下のとおり。
reduce()
のコールバックは、各時点までに蓄積された処理結果(たとえば$carry
)と、その時点で処理される要素(たとえば$element
)の2つの引数をとる- コールバックの戻り値は、受け取った
$carry
に対して$element
に関して処理された新たな$carry
の内容 - 最終的な
reduce()
の戻り値として、$carry
の縮退結果が返される
1 |
$collection->reduce(function($carry, $element) { return 次の$carryに渡す結果; }); |
以下はコレクションの各要素の和を求める例で、縮退の初期値を0
としてreduce()
の第2引数で与え、第1引数のコールバックでは$carry
に各要素の値を足し込んでいる。
1 2 3 4 5 6 7 |
$collection = collect([1, 2, 3, 4, 5]); $reduced = $collection->reduce(function($carry, $element) { return $carry + $element; }, 0); dd($reduced); |
結果は1~5までの和になる。
1 |
15 |
以下は初期値を0→900に変更した例。
1 2 3 |
$reduced = $collection->reduce(function($carry, $element) { return $carry + $element; }, 900); |
初期値0
ではなく900
に対する足し込みとなっている。
1 |
915 |
また次の例では、要素の値を文字列として後ろにつなげていく。初期値には空文字列''
を指定している。
1 2 3 |
$reduced = $collection->reduce(function($carry, $element) { return $carry . $element; }, ''); |
結果は以下のように、値がつなげられた文字列になる。
1 |
"12345" |
連想配列への適用
以下の連想配列を使う。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 |
>>> $p => Illuminate\Support\Collection {#4355 all: [ [ "name" => "Egawa", "gender" => "male", "height" => 175, ], [ "name" => "Iwata", "gender" => "female", "height" => 163, ], [ "name" => "Okada", "gender" => "male", "height" => 168, ], [ "name" => "Ando", "gender" => "male", "height" => 182, ], [ "name" => "Ueda", "gender" => "female", "height" => 167, ], ], } |
filter()
連想配列のコレクションにフィルターを適用する場合。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
>>> $p->filter(function($element) { return $element['gender'] === 'female'; }) => Illuminate\Support\Collection {#4352 all: [ 1 => [ "name" => "Iwata", "gender" => "female", "height" => 163, ], 4 => [ "name" => "Ueda", "gender" => "female", "height" => 167, ], ], } |
ただしこれはwhere()
による操作で代替できる。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
>>> $p->where('gender', '=', 'female') => Illuminate\Support\Collection {#4358 all: [ 1 => [ "name" => "Iwata", "gender" => "female", "height" => 163, ], 4 => [ "name" => "Ueda", "gender" => "female", "height" => 167, ], ], } |
map()
連想配列のコレクションにmap()
を適用した例。gender
キー列の値に応じて内容を書き換えている('male'
→'m'
、'female'
→'f'
)。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 |
>>> $p->map(function($element) { ... $element['gender'] = ($element['gender'] === 'male' ? 'm' : 'f'); ... return $element; ... }) => Illuminate\Support\Collection {#4351 all: [ [ "name" => "Egawa", "gender" => "m", "height" => 175, ], [ "name" => "Iwata", "gender" => "f", "height" => 163, ], [ "name" => "Okada", "gender" => "m", "height" => 168, ], [ "name" => "Ando", "gender" => "m", "height" => 182, ], [ "name" => "Ueda", "gender" => "f", "height" => 167, ], ], } |
また以下の例では、groupBy()
でグルーピングされたコレクションに対してmap()
を適用し、グループごとの要素数をカウントしている(グルーピングと集計参照)。
1 2 3 4 5 6 7 |
>>> $p->groupBy('gender')->map(function($group) { return $group->count(); }) => Illuminate\Support\Collection {#4364 all: [ "male" => 3, "female" => 2, ], } |
reduce()
以下は連想配列のコレクションに対してreduce()
を適用して、要素のheight
キー列の値の二乗和を求め、その結果から分散を計算している。
1 2 3 4 5 6 |
>>> $sum2 = $p->reduce(function($carry, $element) { ... return $carry + $element['height']^2; ... }, 0) => 849 >>> ($sum2 - $p->average('height')^2) / $p->count() => 135.2 |
なおコールバックにuse
を使い、処理中の要素がコレクションの末尾要素のときに、集計結果を使った計算をさせ、reduce()
の結果が直接分散となるようにもできる。
1 2 3 4 5 6 7 8 |
$sum2 = $p->reduce(function($carry, $element) use($p) { if ($element == $p->last()) { $result = $carry + $element['height']^2; return ($result - ($p->average('height'))^2) / $p->count(); } else { return $carry + $element['height']^2; } }, 0) |