Squeak の Smalltalk にあるコレクションブロックメソッド

ファウラーが取りあげた基本的なメソッド以外に、Squeak 3.8 の Smalltalk にはどんなものがあるか a SequenceableCollection で使えるものについてまとめてみました。これらのメソッドの定義(と若干のドキュメントっぽいコメント。ただし残念ながらすべて英語)はシステムブラウザで SequenceableCollection を呼び出し、その enumerating プロトコルから見ることができます。

#do:separatedBy:

繰り返し処理の間隙で第二引数ブロックを評価する。

| stream |
stream := WriteStream on: String new.
(1 to: 10)
   do:  [:each | stream nextPutAll: each printString]
   separatedBy: [stream nextPutAll: ', '].
^ stream contents
=> '1, 2, 3, 4, 5, 6, 7, 8, 9, 10'

#allButFirstDo: , #allButLastDo:

コレクションの最初(#allButFirstDo:)もしくは最後(#allButLastDo:)の要素を無視して #do: 。

#(nil 1 2 3 4 5) allButFirstDo: [:each | Transcript cr; show: each printString]
#(1 2 3 4 5 nil) allButLastDo: [:each | Transcript cr; show: each printString]
=> 1
   2
   3
   4
   5

#do:without:

第二引数と同値のものは排除して #do: 。

#(nil 1 2 3 nil 4 5 nil) do: [:each | Transcript cr; show: each printString] without: nil
=> 1
   2
   3
   4
   5

#reverseDo:

逆順に #do: 。

#associationsDo:

#keysAndValuesDo: 同様、a Dictionary の振る舞いを真似るためのメソッド。#do: と同じ。

#from:to:do: , #collect:from:to:

指定範囲の #do: と #collect: 。

'smalltalk' from: 3 to: 5 do: [:each | Transcript space; show: each printString]
=> $a $l $l
'smalltalk' collect: [:each | each asUppercase] from: 3 to: 5   " => 'ALL' "

#count:

条件に合致した要素の数をカウント。

'squeak' count: [:each | each isVowel]   " => 3 "

#detectMax: , #detectMin:

ブロックを評価した値が、最大(#detectMax:)もしくは最小(#detectMin:)になる要素を返す。当然、ブロック評価時の各返値は互いに比較可能でないといけない(ふつうは数値になるようにする)。#max 、#min のブロック版。

'squeak' detectMax: [:each | each asciiValue]   " => $u "
'squeak' detectMin: [:each | each asciiValue]   " => $a "
'squeak' max   " => $u "
'squeak' min   " => $a "

#findFirst: , #findLast:

条件に合致する要素をうち、最初(#findFirst:)もしくは最後(#findLast:)のもののインデックスを返す。なお、Smalltalk のコレクションのインデックスは 0 ではなく 1 からはじまります。

'smalltalk' findFirst: [:each | each isVowel]   " => 3 "
'smalltalk' findLast: [:each | each isVowel]   " => 7 "

#findBinaryIndex:, findBinaryIndex:ifNone:, findBinary:, findBinary:ifNone:

二分木検索。ブロック評価の結果が 0 になる要素を探します。レシーバ内の要素は、ブロック評価値で降順になるようにソートされている必要があります。

#(8 10 23 27 39 45 59 74 80 86) findBinaryIndex: [:each | 27 - each] ifNone: [0]   " => 4 "

#pairsDo: , #pairsCollect:

先頭から二つずつの要素について #do: あるいは #collect:。

(1 to: 10) pairsCollect: [:a :b | (a/b)]   " => #((1/2) (3/4) (5/6) (7/8) (9/10)) "

#groupsOf:atATimeDo: , #groupsOf:atATimeCollect:

#pairsDo: 、#pairsCollect: の n 個(n > 2)バージョン。

(1 to: 9) groupsOf: 3 atATimeDo: [:each | Transcript cr; show: each]
=> #(1 2 3)
   #(4 5 6)
   #(7 8 9)
(1 to: 9) groupsOf: 3 atATimeCollect: [:each | each sum]   " => #(6 15 24) "

#with:do: , #reverseWith:do: , #with:collect:

レシーバと同じサイズのコレクションの各要素も抽出してブロックを評価します。

($a to: $d) with: (1 to: 4) do: [:a :b | Transcript cr; show: (a -> b) printString]
=> $a->1
   $b->2
   $c->3
   $d->4
($a to: $d) reverseWith: (1 to: 4) do: [:a :b | Transcript cr; show: (a -> b) printString]
=> $d->4
   $c->3
   $b->2
   $a->1
($a to: $d) with: (1 to: 4) collect: [:a :b | a -> b]   " => #($a->1 $b->2 $c->3 $d->4) "

#withIndexCollect:

#withIndexDo: の #collect: 版。

($a to: $d) withIndexCollect: [:each :index | each -> index]   " => #($a->1 $b->2 $c->3 $d->4) "

#collect:thenDo: , #collect:thenSelect: , #select:thenCollect: , #select:thenDo: , #reject:thenDo:

これらいちれんの #operationA:thenOperationB: は、次と同じです。

(receiver operationA: [:each | each doSomething]) operationB: [: each | each doAnotherThing]

ファウラーの例でいえば Python の List Comprehension っぽい雰囲気を出すのに使うことができますが、あくまで雰囲気です。w

'squeak' select: [:each | each isVowel not] thenCollect: [:each | each asUppercase]
=> 'SQK'

#combinations:atATimeDo:

指定数の要素の組み合わせに対して #do: 。

(1 to: 4) combinations: 2 atATimeDo: [:each | Transcript cr; show: each]
=> #(1 2)
   #(1 3)
   #(1 4)
   #(2 3)
   #(2 4)
   #(3 4)

#permutationsDo:

レシーバと同数の重複のない順列に対して #do: 。

'123' permutationsDo: [:each | Transcript cr; show: each printString]
=> '123'
   '132'
   '213'
   '231'
   '321'
   '312'

#asDigitsToPower:do:

第一引数で指定したサイズの重複を許す順列に対して #do: 。

(0 to: 1) asDigitsToPower: 3 do: [:each | Transcript cr; show: each printString]
=> #(0 0 0)
   #(0 0 1)
   #(0 1 0)
   #(0 1 1)
   #(1 0 0)
   #(1 0 1)
   #(1 1 0)
   #(1 1 1)