今回はリスト (java.util.List) について。 『Groovyイン・アクション』Chapter4 とGroovy JDKを参考にしています(一覧)。
- 作者: Dierk Konig,Andrew Glover,Paul King,Guillaume Laforge,Jon Skeet,杉浦孝,櫻井正樹,須江信洋,関谷和愛,佐野徹郎,寺沢尚史
- 出版社/メーカー: 毎日コミュニケーションズ
- 発売日: 2008/09/27
- メディア: 単行本(ソフトカバー)
- 購入: 5人 クリック: 146回
- この商品を含むブログ (121件) を見る
インスタンス生成
List インスタンスの生成には
などがあります。 ここで見ていく List の実装クラスは
です。
ArrayList
扱う List の実装に特に関心がないなら ArrayList を使いましょう。 一応、コンストラクタから直接インスタンスの生成も出来ます。 「リスト展開演算子 *」も使えます(参考)。
def list1 = [1, 2, 3]; assert list1 instanceof ArrayList; def list2 = []; assert list2 instanceof ArrayList; def list3 = new ArrayList(); assert list3 instanceof ArrayList; def list4 = [1, *[2, 3]]; assert list4 == [1, 2, 3]; def list5 = [*list4, 4, 5]; assert list5 == [1, 2, 3, 4, 5];
LinkedList
LinkedList を指定して使用したいときは、コンストラクタを直接呼び出すか、LinkedList に変換する必要があります。
//***** LinkedList ***** def linkedList1 = new LinkedList(); assert linkedList1 instanceof LinkedList; def linkedList2 = new LinkedList([1, 2, 3]); assert linkedList2 instanceof LinkedList; def linkedList3 = [1, 2, 3] as LinkedList; assert linkedList3 instanceof LinkedList;
3つ目が個人的には好き。
List としての Range
Range は List のサブクラスなので、List 型に変換しなくても List として使用できますが、可読性のために toList() メソッドや asType によって、List として使用することを明示しておいたほうが良いかと。
//***** Range ***** def rangeList1 = (1..100); assert rangeList1 instanceof List; def rangeList2 = (1..100).toList(); assert rangeList2 instanceof ArrayList; def rangeList3 = (1..100) as List; assert rangeList3 instanceof List;
その他
toList() メソッドが定義されているクラスから List を生成するのも便利なことが多いかと。
def strList1 = 'ABCDE'.toList(); assert strList1 == ['A', 'B', 'C', 'D', 'E']; def strList2 = 'ABCDE' as List; assert strList2 == ['A', 'B', 'C', 'D', 'E'];
要素の取得と設定 : getAt & putAt
getAt(), putAt() メソッドは要素の取得と設定を行います。 Java API の get(), set() メソッドの拡張です。 基本的にはリストのサイズを変更しません(サイズを超える添字に対する putAt() はサイズを変える)。
メソッド名 | 返り値 | メソッド名 (Generics) |
返り値 (Generics) |
|
---|---|---|---|---|
getAt(int) | Object | getAt(int) | E | |
getAt(Range) getAt(EmptyRange) getAt(Collection) |
List | getAt(Range<int>) getAt(EmptyRange<int>) getAt(Collection<int>) |
List<E> | |
putAt(int, Object) | void | putAt(int, E) | void | |
putAt(IntRange, Object) putAt(IntRange, Collection) putAt(EmptyRange, Object) putAt(EmptyRange, Collection) putAt(List, Object) putAt(List, List) |
void | putAt(IntRange, E) putAt(IntRange, Collection<E>) putAt(EmptyRange<int>, E) putAt(EmptyRange<int>, Collection<E>) putAt(List<int>, E) putAt(List<int>, List<E>) |
void |
表の右2列の Generics は List<E> に対して勝手に書いてます*1。 Groovy に型指定なんてしても仕方ないかと思いますが。
以下、メソッドの使用例を見ていきます:
//***** getAt(int) ***** list = ['a', 'b', 'c', 'd', 'e', 'f']; assert list[1] == 'b'; assert list[-1] == 'f'; assert list[6] == null;
- 負の添字も使えます。 取得方法は、リストの末尾から逆に数えていきます。
- サイズを超えた添字では null が返されます。
//***** get(IntRange) など ***** list = ['a', 'b', 'c', 'd', 'e', 'f']; assert list[1..3] == ['b', 'c', 'd']; //getAt(IntRange) assert list[] == []; // getAt(EmptyRange) assert list[1, 3, 5] == list[[1, 3, 5]]; // getAt(Collection) その1 assert list[1, 3, 5] == ['b', 'd', 'f']; assert list[1, 5, 3] == ['b', 'f', 'd']; set = [0, 1] as HashSet; resultList = list[set]; // getAt(Collection) その2 assert resultList == ['a', 'b'] || resultList == ['b', 'a'];
- getAt(IntRange) などでは、逆順序の範囲や負の添字も使えますが、見た目にややこしいものは使わないのが無難。
- getAt(Collection) は引数に List 以外のコレクションは使わない方が良いかと(順序が不明なのに返り値は List)。
//***** put(int, Object) ***** list = ['a', 'b', 'c']; list[1] = 'x'; assert list == ['a', 'x', 'c']; list = ['a', 'b', 'c']; list[-1] = 'x'; assert list == ['a', 'b', 'x']; list = ['a', 'b', 'c']; list[4] = 'x'; assert list == ['a', 'b', 'c', null, 'x'];
- getAt(int) と同じように負の添字も使えます。 設定される箇所も getAt(int) と同じ。
- サイズを超えた添字では List のサイズが拡張されて設定されます。 途中は null で穴埋め。
//***** put(IntRange, Object) など ***** list = ['a', 'b', 'c']; list[1..2] = 'x'; // putAt(IntRange, Object) assert list == ['a', 'x']; // list != ['a', 'x', 'x'] list = ['a', 'b', 'c']; list[1..2] = ['x', 'y']; // putAt(IntRange, Collection) その1 assert list == ['a', 'x', 'y']; list = ['a', 'b', 'c']; list[1..2] = ['x', 'y', 'z']; // putAt(IntRange, Collection) その2 assert list == ['a', 'x', 'y', 'z']; list = ['a', 'b', 'c']; list[1..2] = []; // putAt(IntRange, Collection) その3 assert list == ['a']; list = ['a', 'b', 'c']; list[] = 'x'; // putAt(EmptyRange, Object) assert list == ['a', 'b', 'c']; //list = ['a', 'b', 'c']; //list[] = ['x', 'y']; // putAt(EmptyRange, Collection) //assert list == ['a', 'b', 'c']; list = ['a', 'b', 'c']; list[0, 2] = 'x'; // putAt(List, Object) assert list == ['x', 'b', 'x']; list = ['a', 'b', 'c']; list[0, 2] = ['x', 'y']; // putAt(List, List) assert list == ['x', 'b', 'y'];
- putAt(IntRange, Object) などでも、getAt(IntRange) などと同じように、ややこしい逆順序や負の添字は使わない方が無難。
- putAt(EmptyRange, Collection) は例外が投げられます(Groovy 1.7 では)。
- putAt(List, List) では、2つの引数の List のサイズが異なると例外が投げられます。
要素の追加と削除 : plus & minus
plus(), minus() メソッドは要素の追加と削除を行います。 Java API の add(), addAll(), remove(), removeAll メソッドなどの拡張です。 基本的にリストのサイズを変更します(追加、削除が成功すれば)。
メソッド名 | 返り値 | メソッド名 (Generics) |
返り値 (Generics) |
備考 | |
---|---|---|---|---|---|
plus(Object) plus(Collection) |
Collection | plus(E) plus(Collection<E>) |
Collection<E> | Collection に定義されてます | |
minus(Object) minus(Collection) |
List | minus(E) minus(Collection<E>) |
List<E> | ||
leftShift(Object) | Collection | leftShift(E) | Collection<E> | Collection に定義されてます |
注意が必要なのは、要素が追加、削除されるのは plus(), minus() メソッド(+, - 演算子)の返り値のリストであることでしょうか。 元々のリストは変更されないので、変数の再代入(もしくは +=, -= 演算子)が必要です。
plus(), +
//***** plus() ***** list = []; list += 'a'; // plus(Object) assert list == ['a']; list += ['b', 'c']; // plus(Collection) assert list == ['a', 'b', 'c'];
minus(), -
//***** minus() ***** list = ['a', 'b', 'c', 'd']; list -= 'c'; // minus(Object) assert list == ['a', 'b', 'd']; list -= ['a', 'd']; // minus(Collection) assert list == ['b'];
leftShift, <<
//***** leftShift() ***** list = []; list << 'a'; // leftShift(Object) assert list == ['a']; list << 'b' << 'c'; assert list == ['a', 'b', 'c'];
leftShift() は再代入をする必要はない模様。
リストと制御構造
これらに関連するメソッドは下表:
メソッド名 | 返り値 | 備考 |
---|---|---|
asBoolean() | boolean | Collection に定義されてます |
isCase(Object) | boolean | Collection に定義されてます |
if 文
要素が空なら false、そうでないなら true
list = [1, 2, 3]; if(list) assert true; else assert false; list = []; if(list) assert false; else assert true;
switch-case 文
list = ['A', 'B', 'C', 'D']; switch('C'){ case list: assert true; break; default: assert false; } switch('c'){ case list: assert false; break; default: assert true; }
grep()
list = ('A'..'D') as List; target = 'PASSWORD'.toList(); // target == ['P', 'A', 'S', 'S', 'W', 'O', 'R', 'D'] assert target.grep(list) == ['A', 'D'];
for-in 文
log = ''; for(i in [1, 'x', 5]) log += i; assert log == '1x5';
*1:仕様とかではなく、正確でもありません。 コンパイルも通りません