Groovy 1.8.1以降で追加されたGDKメソッド(主にコレクション関係)を解説するシリーズ第5段、「collectAllのcollectNestedへのリネーム、collectManyの新規追加」です。とりあえずこれでシリーズ打ち止め予定です。
collect系とfind系の概括的な違い
まずは、自明かもしれませんが、collect系とfind系との違いを示します。
collect系GDKメソッド一覧
以下に、Groovy 1.8.1でのcollect系のメソッドを列挙しておきます。
- List collect(Closure closure)★
- Collection collect(Collection collection, Closure closure) →追加的な1
- List collectAll(Closure closure) → 5の別名
- Collection collectAll(Collection collection, Closure closure) →追加的な3。6の別名
- List collectNested(Closure closure) ★
- Collection collectNested(Collection collection, Closure closure) →追加的な5
- Collection collectMany(Closure closure) ★
- Map collectEntries(Closure closure) ★
- Map collectEntries(Map result, Closure closure) →追加的な8
太字の5,6,7が1.8.1で追加されたメソッドです。
いっぱいあるように見えますが、2、4、6、9の意味はそれぞれ1、3、5、8と同じで、ただし変換した結果を格納する初期値としてのコレクションを引数に与えるバージョンであり、処理結果を引数のコレクションに追加していきます(上の列挙では「追加的なx」と記述しました)。また、後述のようにcollectAll(3,4)はcollectNested(5,6)の別名という扱いになったので、本質的には1、5、7、8の4つ(★)の意味を押さえておけば良いわけです。
collectAllのcollectNestedへのリネーム
Groovyでは1.8.1では以下のメソッドが追加されました。(前述の5と6)
- public List collectNested(Closure closure)
- public Collection collectNested(Collection collection, Closure closure)
とはいうもの、従来の「collectAll」が「collectNested」にリネームされた*3というものなので、collectNetedの意味は、従来のcollectAllと同じです。
collectAll改めcollectNestedの意味は、おさらいになりますが、コレクションのすべての要素(コレクションがコレクションを含んでいるなら、再帰的にコレクション内の要素をたどって)について、引数に指定したクロージャで変換した値を、もとの再帰構造を保存したコレクションの形で返却するというものです。
collectNestedとcollectの違いは、collectは要素であるコレクションを再帰的にたどることはしないということです。collectはトップレベルのコレクションの要素数に等しい回数しかクロージャが呼ばれません。
assert [1,2,[3,4],5].collectNested{it*2} == [2,4,[6,8],10] assert [1,2,[3,4],5].collectAll{it*2} == [2,4,[6,8],10] // collectNestedと同じ assert [1,2,[3,4],5].collect{it*2} == [2,4,[3,4,3,4],10] // [3,4]*2 = [3,4,3,4]。 // リスト[3,4]に再帰的に適用されるのではなく、[3,4]という1つの要素としてあつかわれている
collectManyの新規追加
さらに、Groovyでは1.8.1では以下のメソッドが追加されました。(前述の7)
- public Collection collectMany(Closure closure)
結局のところ、Groovy 1.8.1でcollect系に本当に新しく追加されたメソッドはこのcollectManyのみです。
collectManyは、collectと同様に、変換元のコレクションの要素にコレクションが含まれていても再帰的にたどることはしません。
collectManyの特徴は、変換クロージャの返り値がリスト(など)なので、複数もしくは0個の値を返せる、という点です。リストに含まれる値は結果のコレクションにフラットに追加されます。
なので、コレクションからコレクションの変換に際して、要素が1対1対応にはならない変換を行うことができます。
assert [1,2,3].collectMany{[it*3, it*3+1]} == [3,4,6,7,9,10]
追記。collectManyはflatMapです。
まとめ
collect系をまとめてみました。
項番 | GDKメソッド | 説明 | 入れ子になったコレクションの処理 | 結果 |
---|---|---|---|---|
1 | List collect(Closure closure) | 再帰的にたどらない | 要素に対してclosureを適用した結果からなるリスト | |
2 | Collection collect(Collection collection, Closure closure) | 追加的な1 | 1と同じ | 要素に対してclosureを適用した結果からなるコレクション |
3 | List collectAll(Closure closure) | 5の別名 | 5と同じ | 5と同じ |
4 | Collection collectAll(Collection collection, Closure closure) | 追加的な3。6の別名 | 6と同じ | 6と同じ |
5 | List collectNested(Closure closure) | 再帰的にたどる | 要素に対してclosureを適用した結果からなる、入れ子構造を保ったリスト | |
6 | Collection collectNested(Collection collection, Closure closure) | 追加的な5 | 5と同じ | 要素に対してclosureを適用した結果からなる、入れ子構造を保ったコレクション |
7 | Collection collectMany(Closure closure) | 再帰的にたどらない | 要素に対してclosureを適用した結果をフラット化して接続したコレクション | |
8 | Map collectEntries(Closure closure) | マップを対象 | 再帰的にたどらない | マップに含まれるエントリ(Key,Value)に対してclosureを適用した結果からなるマップ |
9 | Map collectEntries(Map result, Closure closure) | 追加的な8 | 8と同じ | 8と同じ |
ここでも太字が1.8.1で追加されたメソッドです。
Collection collectMany(Collection collection, Closure closure)が無いのが気になるな…。
以上でGroovy 1.8.1におけるコレクションGDKメソッドに対する変更の主要部分の説明は終りです。あと何個か残ってた気もするので、つづくかも。読んで下さった方、おつかれさまでした、ありがとー。