倭マン's BLOG

くだらない日々の日記書いてます。 たまにプログラミング関連の記事書いてます。 書いてます。

GDK のコレクションがこんなに便利なわけがない。 (Collection 編5) その他の集合生成

今回は GDK が Collection クラスに追加している、いろいろなコレクションを生成するメソッドを見ていきます。 「コレクションを生成する」と言っても、(static) ファクトリ・メソッドを集めて見ていくというわけではなく、メソッドの返り値がコレクションなんだけど、ちょっと他の分類に入れにくいなぁというものをまとめて見ていく感じです。 今回扱う unique() や sort() が「コレクションを生成する」というなら、今までに扱った collect() や findAll()、なんなら plus() や leftShift() だって「コレクションを生成する」と言えなくもないですからねぇ。 ということで、今回の分類はあんまり気にしないで下さいな。 これを踏まえて、今回見ていくメソッドは以下のもの:

List multiply(Number factor)

Collection unique()
Collection unique(Closure closure)
Collection unique(Comparator comparator)
Collection unique(boolean mutate)
Collection unique(boolean mutate, Closure closure)
Collection unique(boolean mutate, Comparator comparator)

List sort()
List sort(Closure closure)
List sort(Comparator comparator)
List sort(boolean mutate)
List sort(boolean mutate, Closure closure)
List sort(boolean mutate, Comparator comparator)
  • multiply() は Groovy では「*演算子として使えます
  • unique() と sort() は使い方が似てますな

各メソッドを表にする以下の通り:

メソッド 返り値 since 説明
multiply(Number) List 1.0 元のコレクションの要素を引数の回数だけ繰り返したコレクションを返す
unique()
unique(Closure)
unique(Comparator)
unique(boolean)
unique(boolean, Closure)
unique(boolean Comparator)
Collection 1.0
1.0
1.0
1.8.1
1.8.1
1.8.1
重複した要素を省いたコレクションを返す
sort()
sort(Closure)
sort(Comparator)
sort(boolean)
sort(boolean, Closure)
sort(boolean, Comparator)
List 1.0
1.0
1.0
1.8.1
1.8.1
1.8.1
要素を指定した順序に並べ替えたコレクションを返す

では、各メソッドのサンプルを見ていきましょう。

multiply() メソッド

multiply() メソッドは元の要素を指定回数だけ繰り返したコレクションを生成します。 Groovy では「*」演算子を使って multiply() メソッドを呼び出せます:

assert ['Groovy'] * 3 == ['Groovy', 'Groovy', 'Groovy']
assert ['Java', 'Groovy'] * 3 == ['Java', 'Groovy', 'Java', 'Groovy', 'Java', 'Groovy']

要素が1つの場合は java.util.Collections#fill() と同じような処理ですかね。

unique() メソッド

unique() は重複した要素の2つ目以降を削除したコレクションを返します。 boolean 値の引数は元のコレクション自体を変更するかどうか(true なら変更する、デフォルトは true)、クロージャの引数はその処理結果の equals() で2つの要素を同じと見做すかどうかを評価する、Comparator の引数は2つの要素の比較アルゴリズムをそれぞれ指定します。 デフォルトで(boolean 値を指定しないと)元のコレクションが変更されてしまうので注意。 Java の標準 API や Groovy 1.0 あたりの互換性から仕方ないかと思いますが、関数型言語が流行ってる昨今では少々逆風な気も。 まぁ、変更されるかどうかを指定できるだけでもヨシとする?

def langsDup0 = ['Java', 'Groovy', 'Groovy', 'Scala', 'Java', 'Clojure']

// unique()
assert langsDup0.unique() == ['Java', 'Groovy', 'Scala', 'Clojure']
assert langsDup0 == ['Java', 'Groovy', 'Scala', 'Clojure']    // デフォルトでは元も変更


def langsDup1 = ['Java', 'Groovy', 'Groovy', 'Scala', 'Java', 'Clojure']

// unique(boolean)
assert langsDup1.unique(false) == ['Java', 'Groovy', 'Scala', 'Clojure']
assert langsDup1 == ['Java', 'Groovy', 'Groovy', 'Scala', 'Java', 'Clojure']    // 変更されない


def langsDup2 = ['Java', 'Groovy', 'Scala', 'Clojure', 'Jython', 'JRuby', 'Smalltalk', 'COBOL']

// unique(boolean, Closure)
assert langsDup2.unique(false){ it[0] } == ['Java', 'Groovy', 'Scala', 'Clojure']
    // 頭文字で同じかどうかを評価
assert langsDup2.unique(false){ it.size() } == ['Java', 'Groovy', 'Scala', 'Clojure', 'Smalltalk']
    // 文字列長で同じかどうかを評価

// unique(boolean, Comparator)
assert langsDup2.unique(false){ s0, s1 -> s0.size() - s1.size() } == 
        ['Java', 'Groovy', 'Scala', 'Clojure', 'Smalltalk']

個人的にはずっと false を指定して使いそう。 なんか、カテゴリか拡張モジュールでも作って一貫してイミュータブルな振る舞いをするようにしたいもんだ。

sort() メソッド

sort() は各要素を並べ替えるメソッド。 引数は unique() と似通っております。 boolean 値は元のコレクションを変更するかどうか(true なら変更する、デフォルトは true)、クロージャと Comparator の引数は順序を決定するアルゴリズムを指定します。 クロージャの返り値は Comparable でないといけないでしょうね。 使い方はこんな感じ:

def langs0 = ['Java', 'Groovy', 'Scala', 'Clojure']

// sort()
assert langs0.sort() == ['Clojure', 'Groovy', 'Java', 'Scala']
assert langs0 == ['Clojure', 'Groovy', 'Java', 'Scala']    // デフォルトで元が変更される


def langs1 = ['Java', 'Groovy', 'Scala', 'Clojure']

// sort(boolean)
assert langs1.sort(false) == ['Clojure', 'Groovy', 'Java', 'Scala']
assert langs1 == ['Java', 'Groovy', 'Scala', 'Clojure']    // 元が変更されない

// sort(boolean, Closure)
assert langs1.sort(false){ it.size() } == ['Java', 'Scala', 'Groovy', 'Clojure']
    // 文字列長で並べ替え

// sort(boolean, Comparator)
assert langs1.sort(false){ s0, s1 -> s0.size() - s1.size() } ==
        ['Java', 'Scala', 'Groovy', 'Clojure']
    // これも文字列長で並べ替え

まぁ、元のコレクションを変更するかどうかに気を付ければなんてことないですね。

次回はコレクションの各要素を走査してなんらかの値を計算する Reduce 処理を行うメソッドを見ていく予定。

プログラミングGROOVY

プログラミングGROOVY