Collection (データの集合)
データの集まりを表現するのがCollectionです。
参考資料
Collectionに関してはJava Tutorialが詳しい
JavaのCollection関連クラスのInterface階層
Collection interfacedeは以下のようなメソッドを、List, Setなどの共通項として持っている。
つまり、List, Setインターフェースを実装しているLinkedList, ArrayList, TreeSet, HashSetなどでこれらのメソッドを共通して使えることになる。
public interface Collection<E> extends Iterable<E> {
// Basic operations
int size(); // 含まれる要素の数を返す
boolean isEmpty(); // 空のとき、true
boolean contains(Object element); // 要素elementを含んでいるならtrue
boolean add(E element); //optional 新しい要素elementを追加する
boolean remove(Object element); //optional 要素element を削除する
Iterator<E> iterator(); // 全要素を巡回するためのIteratorを返す
// Bulk operations
boolean containsAll(Collection<?> c);
boolean addAll(Collection<? extends E> c); //optional
boolean removeAll(Collection<?> c); //optional
boolean retainAll(Collection<?> c); //optional
void clear(); //optional 空っぽにする
// Array operations
Object[] toArray();
<T> T[] toArray(T[] a);
}
使用例
1から10までの数を含むリストを作りたい
ArrayList<Integer> intList = new ArrayList<Integer>();
for(int i=1; i<=10; i++)
intList.add(i);
for(int val : intList)
{
System.out.println(val);
}
結果
1
2
3
4
5
6
7
8
9
10
順不同なデータを、ソート(並び替え)したい
ArrayList<Integer> intList = new ArrayList<Integer>();
intList.add(10); // [10]
intList.add(3); // [10, 3]
intList.add(5); // [10, 3, 5]
intList.add(5); // [10, 3, 5, 5]
intList.add(15); // [10, 3, 5, 5, 15]
System.out.println(intList); // [10, 3, 5, 5, 15]
Collections.sort(intList);
System.out.println(intList); // [3, 5, 5, 10, 15]
常にソートされた状態にしておきたい (ただし重複はなし)
TreeSet<Integer> sortedSet = new TreeSet<Integer>();
sortedSet.add(10); // [10]
sortedSet.add(3); // [3, 10]
sortedSet.add(1); // [1, 3, 10]
sortedSet.add(8); // [1, 3, 8, 10]
重複ありの場合
重複ありのリストを管理したい場合には、Google Collection LibraryにあるMultiSet, MultiMapなどを使うとよいかもしれないが、Comparatorを工夫して、要素の比較演算を自ら定義すると、SortedSetなどでも重複データは扱える。
自分で作ったオブジェクトを格納したい
レポート課題のGenomeSequenceクラスを例に。GenomeSequenceクラスにtoString()メソッドを定義しておくと、コレクションの中身の確認がしやすくなります。
public String toString() {
return String.format("%s: %s", name, sequence);
}
LinkedList<GenomeSequence> sequenceList = new LinkedList<GenomeSequence>();
sequenceList.add(new GenomeSequence("seq0001", "AATTGG"));
sequenceList.add(new GenomeSequence("seq0003", "TAG"));
sequenceList.add(new GenomeSequence("seq0002", "CCGGGCC"));
sequenceList.add(new GenomeSequence("seq0010", "CGTTT"));
sequenceList.add(new GenomeSequence("seq000A", "ACGT"));
LinkedListとArrayList
LinkedListは数珠つなぎに要素を結合していくデータ構造で挿入に強い。ArrayListの中身は固定長の配列。要素の挿入時に、挿入位置より後ろの要素をすべて移動しなくてはならないので、速度が遅くなるときがある。
自分で作ったオブジェクトを並び替えたい
Comparatorを使う方法
LinkedList<GenomeSequence> sequenceList = new LinkedList<GenomeSequence>();
sequenceList.add(new GenomeSequence("seq0001", "AATTGG"));
sequenceList.add(new GenomeSequence("seq0003", "TAG"));
sequenceList.add(new GenomeSequence("seq0002", "CCGGGCC"));
sequenceList.add(new GenomeSequence("seq0010", "CGTTT"));
sequenceList.add(new GenomeSequence("seq000A", "ACGT"));
System.out.println(sequenceList);
// [seq0001: AATTGG, seq0003: TAG, seq0002: CCGGGCC, seq0010: CGTTT, seq000A: ACGT]
Collections.sort(sequenceList, new Comparator<GenomeSequence>() {
// クラス定義をメソッド呼び出し中で行うというテクニック
public int compare(GenomeSequence s1, GenomeSequence s2) {
return s1.getName().compareTo(s2.getName());
}
});
System.out.println(sequenceList);
// [seq0001: AATTGG, seq0002: CCGGGCC, seq0003: TAG, seq000A: ACGT, seq0010: CGTTT]
Comparableを実装し、Setを利用する方法
sequenceの名前の辞書順で並び替えを行いたい場合
class GenomeSequence implements Comparable<GenomeSequence> {
(中略)
public int compareTo(GenomeSequence other) {
return name.compareTo(other.getName());
}
}
TreeSet<GenomeSequence> sequenceSet = new TreeSet<GenomeSequence>();
sequenceSet.add(new GenomeSequence("seq0001", "AATTGG"));
sequenceSet.add(new GenomeSequence("seq0003", "TAG"));
sequenceSet.add(new GenomeSequence("seq0002", "CCGGGCC"));
sequenceSet.add(new GenomeSequence("seq0010", "CGTTT"));
sequenceSet.add(new GenomeSequence("seq000A", "ACGT"));
System.out.println(sequenceSet);
// [seq0001: AATTGG, seq0002: CCGGGCC, seq0003: TAG, seq000A: ACGT, seq0010: CGTTT]
Iteratorを使ってCollectionを巡回したい
TreeSet<GenomeSequence> sequenceSet = new TreeSet<GenomeSequence>();
sequenceSet.add(new GenomeSequence("seq0001", "AATTGG"));
sequenceSet.add(new GenomeSequence("seq0003", "TAG"));
sequenceSet.add(new GenomeSequence("seq0002", "CCGGGCC"));
sequenceSet.add(new GenomeSequence("seq0010", "CGTTT"));
sequenceSet.add(new GenomeSequence("seq000A", "ACGT"));
for(Iterator<GenomeSequence> it = sequenceSet.iterator(); it.hasNext(); )
{
GenomeSequence seq = it.next();
System.out.println(seq.toString());
}
/*
以下のように表示される
seq0001: AATTGG
seq0002: CCGGGCC
seq0003: TAG
seq000A: ACGT
seq0010: CGTTT
*/
IteratorはSet, Listなどに共通して使える。
データに早くアクセスするための索引を作りたい Map
LinkedList<GenomeSequence> sequenceList = new LinkedList<GenomeSequence>();
sequenceList.add(new GenomeSequence ("seq0001", "AATTGG"));
sequenceList.add(new GenomeSequence("seq0003", "TAG"));
sequenceList.add(new GenomeSequence("seq0002", "CCGGGCC"));
sequenceList.add(new GenomeSequence("seq0010", "CGTTT"));
sequenceList.add(new GenomeSequence("seq000A", "ACGT"));
// HashMapでは、(key, value)のペアを格納し、keyをO(1)で検索できる
HashMap<String, GenomeSequence> sequenceIndex = new HashMap<String, GenomeSequence>();
for(GenomeSequence seq : sequenceList){
sequenceIndex.put(seq.getName(), seq);
}
GenomeSequence searchResult = sequenceIndex.get("seq0001");
// searchResult = ("seq0001", "AATTGG")
GenomeSequence searchResult2 = sequenceIndex.get("seq00XX");
// searchResult == null
if(sequenceIndex.containsKey("seq000A"))
{
// seq000Aが見つかった
GenomeSequence seq00A = sequenceIndex.get("seq0001");
}
// HashMapでは、keyはsortされていない
for(String key : sequenceIndex.keySet())
{
System.out.println(sequenceIndex.get(key));
}
/*
以下のように(順不同)で表示される
seq0010: CGTTT
seq0001: AATTGG
seq0003: TAG
seq000A: ACGT
seq0002: CCGGGCC
HashMapをTreeMapに変更すると、以下のようになる。
seq0001: AATTGG
seq0002: CCGGGCC
seq0003: TAG
seq000A: ACGT
seq0010: CGTTT
*/
HashMap とTreeMap
HashMapとTreeMapはどちらも(key, value)のペアを格納し、keyの値でvalueを検索するの性能に優れています。keyの並び順を気にしなくてもいい場合は、HashMapの方がO(1) (定数オーダー)で、性能が安定していますが、keyをソートした順でデータを管理したい場合は、TreeMapを使います。TreeMapでは、内部で木構造を使ってデータを管理しているので、keyの検索性能はO(log n)です(nは要素の数、log nは木の高さ)

