コレクション

コレクション

Collectionのサブクラスを紹介。(Array、OrderedCollection、List、Set、Bagなど)
Stringとそのサブクラス(SymbolやByteString)、Dictionaryは別管理しているのでそちらを参照。

Collectionには順番が保障されているタイプ(以下、配列型と表記)とされていないタイプ(以下、集合型と表記)がある。
SequenceableCollectionのサブクラスか否かで決まる。

Collectionのサブクラスのメジャーなクラスの特徴
  • Array: 配列型。リテラルで定義することができる。項目の追加・削除を禁止している。
  • OrderedCollection: 配列型。項目追加・削除ができ、いはゆる配列というイメージに最も近い振る舞いをする。
  • List: 配列型。項目追加・削除ができる。いまいちOrderedCollectionとの使い分けのポイントがわからないが、位置を指定した追加や削除に向いているはず。
  • SortedCollection: 配列型。ソートされた状態が保障されている配列。ソートブロックを内包している。
  • Set: 集合型。重複のない集合。
  • Bag: 集合型。重複を許し、さらに重複項目の重複数まで保持している。
  • SelectionInList: 画面を表示するときのリストボックスに使われる。Listと選択中インデックスを保持している。
  • SelectionInListSortAware: 画面を表示するときのデータセットに使われる。List、選択中インデックス、ソート項目とその方向を保持している。

7.0~のマイナーバージョンアップの間に増えたメソッドも結構あるみたいだ。

作る
空のコレクションを作る
特定の値でコレクションを作る
任意の値のコレクションを作る
コレクション(配列型)を結合する
調べる
コレクションの要素数を調べる
コレクションが空か調べる
コレクションが空でないか調べる
コレクションが空でないか調べる2
コレクション(配列型)があるコレクション(配列型)で始まるか調べる
コレクション(配列型)があるコレクション(配列型)で終わるか調べる
コレクションにある要素が含まれているか調べる
コレクションにある条件に合致する要素が含まれているか調べる
コレクションの全ての要素が条件に合致するか調べる
コレクションの要素のどれか一つ以上が条件に合致するか調べる
探す
コレクション(配列型)のある要素の位置を先頭から探す
コレクション(配列型)のある要素の位置を最後から探す
コレクション(配列型)の要素がある条件にマッチする最初の位置を返す
コレクション(配列型)の要素がある条件にマッチする最後の位置を返す
比較対象のコレクション(配列型)と合致する最初の位置を探す
ある条件に合致する要素を取得する
修正する
コレクション(配列型)の指定した要素を置換する
コレクション(配列型)の指定した範囲を置換する
コレクション(配列型)の一部を置換する
コレクションの各要素を与えた条件に修正する
取り出す
コレクション(配列型)の1文字目を取得する
コレクション(配列型)の最後の文字を取得する
コレクション(配列型)の指定した位置の文字を取得する
コレクション(配列型)の先頭から指定した要素数分を取得する
コレクション(配列型)の最後の指定した要素数分を取得する
コレクション(List、OrderedCollection)の指定した要素の次を取得する
コレクション(List、OrderedCollection)の指定した要素の前を取得する
指定した要素数を先頭から取り除いたコレクション(配列型)を返す
指定した要素数を最後から取り除いたコレクション(配列型)を返す
任意の位置から任意の位置までコレクション(配列型)を切り出す
指定したオブジェクトの手前までを切り出す
指定したオブジェクトを取り除いたコレクションを返す
ある条件に合致する要素だけを残したコレクションを返す
除く
コレクションの指定した要素を取り除く
コレクション(配列型)の最初の要素を取り除く
コレクション(配列型)の最後の要素を取り除く
コレクション(配列型)の指定した位置の要素を取り除く
コレクションの要素を全て取り除く
コレクションから指定したコレクションの要素と一致する要素を全て取り除く
コレクション(配列型)の指定した範囲の要素を取り除く
コレクションから条件に合致する要素を全て取り除く
条件に合致する要素を全て取り除いたコレクションを返す
追加する
コレクション(List、OrderedCollection)の最後に要素を1つ追加する
コレクション(List、OrderedCollection)の最後に要素を追加する2
コレクション(List、OrderedCollection)の最初に要素を追加する
コレクション(List、OrderedCollection)の最後にコレクションを追加する
コレクション(List、OrderedCollection)の最後にコレクションを追加する2
コレクション(List、OrderedCollection)の最初にコレクションを追加する
コレクション(List、OrderedCollection)のafter:で指定した要素の後に要素を追加する
コレクション(List、OrderedCollection)のafter:で指定した要素の前に要素を追加する
コレクション(List、OrderedCollection)の指定した位置の前に要素を追加する
コレクションをコピーしつつ最後に要素を1つ追加する
Bagに出現頻度付きで要素を1つ追加する
ループする
コレクションの各要素に対し順番に処理を行う
コレクション(配列型)のインデックスに対し順番に処理を行う
コレクション(配列型)の各要素・インデックスに対し同時指定で順番に処理を行う
コレクションの各要素に対し順番に処理を行いつつ合間にも処理を行う
同じサイズのコレクション(配列型)同士で各要素に対し順番に処理を行う
並べ替える
コレクションをソート済コレクション(SortedCollection)にする
コレクションを条件指定でソート済コレクション(SortedCollection)にする
コレクション(配列型)を破壊的にソートする
コレクション(配列型)を条件指定で破壊的にソートする
コレクション(配列型)を条件指定で破壊的にソートする
コレクション(配列型)の指定した位置同士を入れ替える
結合する
コレクションの各要素をつなげる
コレクションの各要素を重ねあわせる(集計関数っぽいことをやる)
区切る
コレクション(配列型)を指定したトークンで区切る
コレクション(配列型)を条件にマッチする要素で区切る
コレクション(配列型)を条件にマッチする要素で区切りつつループもする
コレクション(配列型)を条件にマッチしない要素で区切る
コレクション(配列型)を条件にマッチしない要素で区切りつつループもする
コレクション(配列型)を要素の前後関係を判断して区切る
コレクション(配列型)を要素の前後関係を判断して区切りつつループもする
まとめる
コレクションをユニークな(重複のない)コレクションにする
コレクションに重複数のデータも持たせる
コレクションをtrue側false側に二分する
その他
コレクションのある要素の重複数を調べる
コレクション(配列型)の順番を反対にする
コレクション(配列型)各要素に対し逆から順番に処理を行う



Array new: 10

まずはここから。適当なクラス new: n とすればだいたいどのクラスでも作成できる。
ただし、メモリ空間を確保しただけで実際に at: n でアクセスするとエラーになるクラスのほうが多い。
終端を表すインスタンス変数(lastIndexとかlimitとかtallyとか)が0のままだからだ。
そういうクラスで終端を後付で変更することなしにアクセスしたい場合は
OrderedCollection withSize: 10
とする。

Array new: 10 withAll: 0

ArrayかStringで理解できる。他のクラスで作りたい場合は(Array new: n withAll: x) asXxxxとする。

(Array new: 5) atAllPut: 0

としてもよい。

任意の値のコレクションを作る
Array(リテラル)の場合
#($a $b 1 2 3 'Hello' #World)

いくつでも設定できる。

Array(withメソッド)の場合
Array with: Date today with: Time now

withは4つまで。そこまでしかメソッドが用意されていない。
もっと作りたい場合は(Array with:with:with:with:),(Array with:)のようにカンマでつなぐ。

OrderedCollectionの場合
(foo := OrderedCollection new) add: 1; add: 2; add: 3; yourself

これ1行でfooの中に3つの項目が入る。

Listの場合
(foo := List new) at:1 put: $a; at:2 put: $b; at:3 put: $c; yourself

これ1行でfooの中に3つの項目が入る。

storeOn:メソッドを読むと、どのように書けばオブジェクトが作れるかわかる。


#($a $b $c), #(1 2 3)


#($a $b $c) size

要素数を調べる。コレクションが空か調べるために aCollection size = 0 ifTrue:[...]とかやるのを見かけるが、
そういう場合は下記のisEmpty等が用意されているのでそれらを使うべきだろう。


Array new isEmpty

コレクションが空の場合trueを返す。


#($a $b $c) isNotEmpty

#($a $b $c) notEmpty

コレクションが空でない場合trueを返す。
isEmptyの逆がどっちかわからなくなってもいいように2種類用意されていると思われる。


#($a $b $c) beginsWith: 'ab'

ArrayとStringで比較しているが、at:メソッドを理解できるクラスなら比較可能。この場合trueになる。


#($a $b $c) endsWith: 'bc'

beginsWith:の逆からメソッド。
ArrayとStringで比較しているが、at:メソッドを理解できるクラスなら比較可能。この場合trueになる。


#('Zun' 'Zun' 'ZUN' 'zun' 'Doko') includes: 'Doko'

要素が含まれていればtrueを返す。
位置まで知りたければindexOfかlastIndexOf:を用いる。ブロックで条件指定したければcontains:を用いる。


#('Zun' 'Zun' 'ZUN' 'zun' 'Doko') contains: [:i | '*zun*' match: i]

条件に合致する要素が含まれていればtrueを返す。
条件に合致する要素を取得したい場合はdetect:を用い、位置を取得したい場合はfindFirst:またはfindLastを用いる。


#(1 3 5 7 9) allSatisfy: [:i | i odd]

全ての要素が条件に合致すればtrueを返す。


#(2 4 6 8 0 1) anySatisfy: [:i | i odd]

要素のどれか一つでも条件に合致すればtrueを返す。


#($a $b $c $b) indexOf: $b

要素が見つからなければエラーになるので、回避策としてindexOf:ifNone:もあり。
ブロックで条件を指定したければfindFirst:を用いる。


#($a $b $c $b) lastIndexOf: $b

indexOfの逆からメソッド。要素が見つからなければエラーになるので、回避策としてlastIndexOf:ifNone:もあり。
ブロックで条件を指定したければfindLast:を用いる。


#($a $B $c $D) findFirst: [:i | i isUppercase]

どの要素も条件に合致しない場合は0を返す。


#($a $B $c $D) findLast: [:i | i isUppercase]

どの要素も条件に合致しない場合は0を返す。


#(1 2 3 4 5 6 7 8 9 0) indexOfSubCollection: (3 to: 6) startingAt: 2

コレクション(配列型)同士の比較を行う。インターバル(3 to: 6)も配列型コレクションのサブクラスなので比較可能。
文字列にも使えるが、文字列の場合はfindString:startingAt:が用意されている。


#('Zun' 'Zun' 'ZUN' 'zun' 'Doko') detect: [:i | '*zun*' match: i]

4つの「ect」メソッドの1つ。
条件に合致する要素が含まれていない場合はエラーになるので、回避策としてdetect:ifNoneもあり。
条件に合致する要素があるか真偽を問う場合はcontains:を用い、位置を取得したい場合はfindFirst:またはfindLastを用いる。
(XXXXX detect: [YYYY] ifNone: [nil]) isNil ifTrue: [ZZZ] なんていうのを見かける。contains:の存在に気づいて欲しい。


'Good morning' beMutable replaceAll: $o with: $a

破壊的メソッドで、リテラル文字列でもbeMutableすれば破壊的修正が可能。文字列で使うことがほとんどだと思う。
開始終了位置を指定できるcopyReplaceFrom:to:with:というメソッドもある。


'Good morning' beMutable replaceFrom: 1 to: 4 with: 'Bad '

破壊的メソッドで、リテラル文字列でもbeMutableすれば破壊的修正が可能。
from:to:の範囲とwith:の文字数が合わないとエラーになる。文字列で使うことがほとんどだと思う。


#($a $b $c $d) copyReplaceAll: 'cd' with: #(1 3)

開始終了位置を指定できるcopyReplaceFrom:to:with:というメソッドもある。配列型コレクション同士なら置換可能。


#(1 2 3) collect: [:i | i * 2]

よく#(1 2 3) do: [:i | i * 2]とやってもコレクションが変わらないと嘆くのを見かけるが、
do:でアクセスする要素はリードオンリーなので、これで対応する。


#($a $b $c) first


#($a $b $c) last


#($a $b $c) at: 2


#($a $b $c) first: 2


#($a $b $c) last: 2


#($a $b $c) asList after: $b

指定した要素が見つからなければエラー、指定した要素が最後の場合もエラー。
findIndexOf:を利用して+1しているだけ。


#($a $b $c) asList before: $b

指定した要素が見つからなければエラー、指定した要素が最初の場合もエラー。
findIndexOf:を利用して-1しているだけ。


#($a $b $c) allButFirst: 1


#($a $b $c) allButLast: 1


#($a $b $c) copyFrom: 1 to: 2

汎用性の高さには定評があるように思う。


#($a $b $c) copyUpTo: $b

長いコレクションになると信頼性は低いだろうなぁ。


#(1 nil 3 nil nil 6 7 nil nil 0) copyWithout: nil

nilを指定すればrubyでいうcompactと同じ動きになる。


#(1 2 3 4 5 6 7 8 9 0) select: [:i | i odd]

4つの「ect」メソッドの1つ。逆に除く場合はreject:を用いる。


foo :=  #($a $b $a $c $a $d) asList.
foo remove: $a

破壊的メソッドで、実行後、コレクションをもう一度見てみると指定した値が除かれている。
また、remove:の返り値は指定した値になる。
指定した要素が見つからない場合はエラーになるので、回避策としてremove:ifAbsentもあり。


foo :=  #($a $b $c) asList.
foo removeFirst

破壊的メソッドで、実行後、コレクションをもう一度見てみると最初の要素が除かれている。
また、removeFirstの返り値は指定した最初の要素の値になる。いはゆるキューを実現できる。
コレクションが空の場合はエラー。


foo :=  #($a $b $c) asList.
foo removeLast

破壊的メソッドで、実行後、コレクションをもう一度見てみると最後の要素が除かれている。
また、removeLastの返り値は指定した最後の要素の値になる。いはゆるスタックを実現できる。
コレクションが空の場合はエラー。


foo :=  #($a $b $c) asList.
foo removeAtIndex: 2.

破壊的メソッドで、実行後、コレクションをもう一度見てみると指定した位置の要素が除かれている。
また、removeAtIndex:の返り値は指定した位置の要素の値になる。
コレクションのサイズより大きい位置を指定した場合はエラー。


foo :=  #($a $b $c) asList.
foo removeAll

破壊的メソッドで、実行後、コレクションをもう一度見てみると空になっている。
また、removeAllの返り値はコレクションの値そのものになる。
実際の動きは1項目ずつremove:するので遅い。


foo :=  #($a $b $c) asList.
foo removeAll: #($a $b)

破壊的メソッドで、実行後、コレクションをもう一度見てみるとコレクションと共通する要素が除かれている。
また、removeAllの返り値はコレクションの共通要素になる。1つでも見つからないとエラーになる。
実際の動きはレシーバと引数の直積になるので遅い。


foo :=  #($a $b $c) asList.
foo removeFrom: 1 to: 2

破壊的メソッドで、実行後、コレクションをもう一度見てみると指定した範囲の要素が除かれている。
また、removeFrom:to:の返り値は指定した範囲のコレクションになる。


foo := #(1 2 3 4 5 6 7 8 9 0) asList.
foo removeAllSuchThat: [:i | i odd]

破壊的メソッドで、実行するとコレクション自身を変更しつつ、条件を満たすものを返り値として抽出することができる。
Visualworks界の最強のキラーメソッドと確信している。実力は中村主水並みだと思う。


#(1 2 3 4 5 6 7 8 9 0) reject: [:i | i odd]

4つの「ect」メソッドの1つ。逆に残す場合はselect:を用いる。
remove系のメソッドと異なり、破壊的ではない。


(OrderedCollection new) add: 1; add: 2; add: 3; yourself

任意の値のコレクションを作るところでも活躍。


(OrderedCollection new) addLast: 1; addLast: 2; addLast: 3; yourself

add:と使い方は同じ。


(OrderedCollection new) addFirst: 1; addFirst: 2; addFirst: 3; yourself

add:やaddFirst:とは逆に、先頭に追加する。


#(1 2 3) asList addAll: #(4 5 6);yourself

コレクションの最後にコレクションを追加する。


#(1 2 3) asList addAllLast: #(4 5 6);yourself

addAll:と使い方は同じ。


#(1 2 3) asList addAllFirst: #(4 5 6);yourself

コレクションの最初にコレクションを追加する。


#($a $b $c) asList add: $d after: $a ;yourself

コレクションを順番に見ていって挿入する位置を探すのでちょっと遅い。


#($a $b $c) asList add: $d before: $a ;yourself

コレクションを順番に見ていって挿入する位置を探すのでちょっと遅い。


#($a $b $c) asList add: $d beforeIndex: 2 ;yourself

add:after:とadd:before:は対になっているのに、なぜかこれはbeforeしかない。


#($a $b $c) copyWith: $d

Arrayは要素を追加することが許されていないが、コピーを作る時についでに追加という感じならOK。


foo := #(1 3 5 8 5 6 2 3 5 7 6 9 5 4) asBag.
foo add: 1 withOccurrences: 9.
foo

既に存在する要素であれば出現数が加算される。


#('Hello' 'World') do: [:i | Transcript cr; show: i]

もっとも基本的なループ。その汎用性ゆえに至る所で使われるが、今一度、do:を使った車輪の再開発をしていないか見直して欲しい。
ちなみにブロック内で使う引数は参照専用なので、do:を使って自身の値を:=で書き換えることはできない。


foo := Array new: 5.
foo keysDo: [:i | foo at: i put: i]

コレクションのインデックスで何かしたいときに使う。自身の配列にアクセスすることも可能。


foo := Array new: 5 withAll: 2.
foo keysAndValuesDo: [:key :val | foo at: key put: val * key]

このメソッドが真価を発揮するのはDictionaryの場合かな。


foo := ''.
#('Zun' 'Zun' 'ZUN' 'zun' 'Doko') do: [:i | foo := foo, '"', i, '"'] separatedBy: [foo := foo, ',']

CSVを作るときに真価を発揮する。逆にそれ以外の使いどころがわからない。


dic := Dictionary new.
brother := #('長男' '次男' '三男' '四男' '五男' '六男').
name := #('おそ松' '唐松' 'チョロ松' '市松' '十姉妹' '椴松').
brother with: name do: [:i :j | dic at: i asSymbol put: j].

2つのコレクションのサイズが異なるとエラーになるんダヨ~ン。
いい例が見つからなかったぜ、てやんでぃ、バーローちきしょう!


並べ替える
並べ替えはいずれもクイックソートで行われるので不安定なソートである。
コレクションをソート済コレクション(SortedCollection)にする
#(7 9 4 5 2 0 1 3) asSortedCollection

SortedCollectionが得られる。つまり、返り値はクラスが変わっている。


(Array with: (#a->9) with: (#b->6) with: (#c->4) with: (#d->2)) asSortedCollection: [:e1 :e2 | e1 value < e2 value]

ソート条件はブロック内に2つの引数が必要。


#(7 9 4 5 2 0 1 3) beMutable sort
#(7 9 4 5 2 0 1 3) beMutable sorted

破壊的メソッドで、実行後、コレクションをもう一度見てみると並べ替えられている。
sortとsortedの違いはいまいちわからない。


(Array with: (#a->9) with: (#b->6) with: (#c->4) with: (#d->2)) sort: [:e1 :e2 | e1 value < e2 value]
(Array with: (#a->9) with: (#b->6) with: (#c->4) with: (#d->2)) sorted: [:e1 :e2 | e1 value < e2 value]
(Array with: (#a->9) with: (#b->6) with: (#c->4) with: (#d->2)) sortWith: [:e1 :e2 | e1 value < e2 value]

破壊的メソッドで、実行後、コレクションをもう一度見てみると並べ替えられている。
sort:とsorted:の違いはいまいちわからない。


#($a $b $c) beMutable swap: 2 with: 3


(Array with: (#a -> 'A') with: (#b -> 'B')) fold: [:i :j | i value, ',', j value]

変数を用意しないでつなげることができるので便利。要素が空だとエラー。
CSVを作るときには要素間だけにカンマを入れてくれるので非常に強力。
また要素が1つだけだと思うような結果にならないこともある。
上記の例は要素を1つにするとvalueが評価されない。


#(1 3 5 7 9) inject: 0 into: [:i :j | i + j]

変数を用意しないでつなげることができるので便利。
上記の例は合計を計算する。
最大値、最小値であれば [:i :j | i min: 9] とか [:i :j | i max: j] とかやればよい。
文字列結合は [:i :j | i, j] でできる。
ただしfoldと違ってCSVを作ろうとするとカンマが余る。


'Morning,Afternoon,Evening' tokensBasedOn: $,

コレクション共通メソッドだが、CSVを区切るために用意したとしか思えない。


'Morning,Afternoon/Evening;Night' runsFailing: [:i | #($, $/ $;) includes: i]

コレクション共通メソッドだが、文字列以外での使いどころがわからない。


'Morning,Afternoon/Evening;Night' runsFailing: [:i | #($, $/ $;) includes: i] do: [:i | Transcript cr; show: i]

コレクション共通メソッドだが、文字列以外での使いどころがわからない。


'123,456,789.321' runsSatisfying: [:i | i isDigit]

runsFailing:の逆条件バージョン。マッチする要素が続く場合、まとめて一区切りとする。


'123,456,789.321' runsSatisfying: [:i | i isDigit] do: [:i | Transcript cr; show: i]

runsFailing:do:の逆条件バージョン。マッチする要素が続く場合、まとめて一区切りとする。


'getFieldKnownNotToBeAName:' piecesCutWhere: [:i :j | i isLowercase and: [j isUppercase]]

コレクション共通だが、やはり文字列向きといえる。これはキャメルケースを単語ごとにカットした場合。


'getFieldKnownNotToBeAName:' piecesCutWhere: [:i :j | i isLowercase and: [j isUppercase]] do: [:i | Transcript cr; show: i]

コレクション共通だが、やはり文字列向きといえる。これはキャメルケースを単語ごとにカットした場合。
do:付きのメソッドをいろいろ用意してあるが、その効果はいかほどのものか疑問に思う。
確かに1度コレクションのコピーを作ってからdo:するよりは効率がいいのだが、使用する頻度を考えるとな。。。


#(1 3 5 8 5 6 2 3 5 7 6 9 5 4) asSet

Setクラスにするだけで重複がなくなる。順番は保障されない。


#(1 3 5 8 5 6 2 3 5 7 6 9 5 4) asBag

Bagクラスにするだけで重複数も一緒に持つことができる。Bagも順番が保障されないタイプ。
重複数はoccurrencesOf:で取得することができる。


#(1 3 5 8 5 6 2 3 5 7 6 9 5 4) groupedBy: [:i | i odd]

tureとfalseをキーとするDictionaryが返る。
実はremoveAllSuchThat:で破壊的に分けることができ、しかも変数も少なくできるので、それを知っていると出番がなくなる。


#(1 3 5 8 5 6 2 3 5 7 6 9 5 4) occurrencesOf: 5

コレクションを1回ループさせてカウントするので、何度も実行するならasBagしてからの方が効率がよい。


#($a $b $c $d $e) reverse

逆にした状態を後々まで保持しておいていろいろ利用するなら使う価値があるかもしれない。
逆からループするなら下記の同時にdo:するタイプを使ったほうが効率がいい。


#($a $b $c $d $e) reverse di: [:i | Transcript cr; show: i]

メソッドはself size to: 1 by: -1 do: []となっている。つまり、reverse:して、コレクションのコピーを
返してから、さらにdo:するよりはずっと効率がいい。

  • 何でもする。舐めてあげるし。入れてあげる。(*´ω`)★ http://gffz.biz/ -- age (2011-11-23 09:41:07)
名前:
コメント:
-

タグ:

+ タグ編集
  • タグ:
最終更新:2013年02月21日 15:14
ツールボックス

下から選んでください:

新しいページを作成する
ヘルプ / FAQ もご覧ください。