No Programming, No Life

プログラミング関連の話題や雑記

GroovyのList#unique()って破壊的だったっけ?

はじめに

タイトルの通りなんですが、以下のようなコードを実行したときに
どうも破壊的に動作するようで…

def list = [1, 1, 2, 2, 3, 3]
assert list.size() == 6

def newList = list.unique() // 破壊的!
assert newList.size() == 3
assert newList == [1, 2, 3]

// ここまではOKなんですが list.unique() したことで
// listが破壊されてしまっている…
assert list.size() == 3
assert list == [1, 2, 3]

// #unique()はそのままlistの参照を返すようで
// 以下のように残念な結果になっている
assert list.is(newList) // Javaで言うところの list == newList (参照が同じ)

個人的にはuniqueした新しいリストが返って来るものとばかり思い込んでいたのでハマりました。

本当はこんな感じだとよかったのに…

// #safeUnique()を定義
List.metaClass.safeUnique = { delegate.clone().unique() }

def list = [1, 1, 2, 2, 3, 3]
assert list.size() == 6

def newList = list.safeUnique() // 非破壊的!
assert newList.size() == 3
assert newList == [1, 2, 3]

// listが破壊されていない
assert list.size() == 6
assert list == [1, 1, 2, 2, 3, 3]

// 残念な結果にならない
assert !list.is(newList)

(動作確認: Groovy Version: 1.8.0-rc-1 JVM: 1.6.0_24)

まとめ

#reverse()は新しいリストを返してくれるんですが、#sort()も同じく破壊的になるようです。
GroovyでList操作する際は破壊的かどうかを見極めてから使う必要がありそうですね。