1 00:00:00,440 --> 00:00:04,440 このセッションでは、イテレータと コレクションについてお話しします。 2 00:00:04,600 --> 00:00:09,000 Pharo でイテレータによって コレクションの中を列挙する方法を見てみましょう。 3 00:00:09,160 --> 00:00:13,000 Pharo のイテレータの力がわかるでしょう。 4 00:00:13,160 --> 00:00:17,640 よく使う主なイテレータを見てみましょう。 5 00:00:17,800 --> 00:00:19,360 最初の例です。 6 00:00:19,520 --> 00:00:22,680 これは Java で書いた 7 00:00:23,880 --> 00:00:25,320 コレクションを列挙するコードです。 8 00:00:25,480 --> 00:00:28,160 コレクション persons を列挙して 9 00:00:28,320 --> 00:00:31,920 名簿を抽出します。 10 00:00:32,480 --> 00:00:35,240 Pharo ではこのコードを書きます。 11 00:00:35,400 --> 00:00:39,880 collect: イテレータを使います。 これについては後でお話しします。 12 00:00:40,040 --> 00:00:43,360 人々の全ての名前を集めます。 13 00:00:43,520 --> 00:00:47,920 ところで、Java の最新版の Java 8 では 14 00:00:48,080 --> 00:00:51,120 レキシカルクロージャを導入しました。 15 00:00:51,280 --> 00:00:53,640 ブロックと等価なものです。 16 00:00:53,800 --> 00:00:57,000 その結果、構文が Pharo に近付きました。 17 00:00:57,160 --> 00:01:00,200 しかし、Pharo では 最初からブロックがありました。 18 00:01:00,360 --> 00:01:02,440 ブロックはこの言語の心臓部です。 19 00:01:02,600 --> 00:01:07,320 プログラマにとても大きな表現力を 与えます。 20 00:01:08,200 --> 00:01:11,320 とても多くのイテレータがあります。 21 00:01:11,480 --> 00:01:16,400 まず collect: があります。コレクションに collect: を送ることで何ができるでしょうか? 22 00:01:16,560 --> 00:01:20,240 これは正や負の数のコレクションです。 23 00:01:20,400 --> 00:01:23,200 collect: メッセージを送って ブロックを渡します。 24 00:01:23,360 --> 00:01:25,560 コレクションを列挙する時は 25 00:01:25,720 --> 00:01:30,160 順番にブロックの引数になります。 2, -3, 4, …という具合に。 26 00:01:30,320 --> 00:01:33,760 そして abs メッセージを送って 絶対値を求めます。 27 00:01:33,920 --> 00:01:36,840 abs メッセージはこの数の絶対値が 欲しいという意味です。 28 00:01:37,000 --> 00:01:40,720 コレクションのそれぞれの要素に対して ブロックを適用したら 29 00:01:40,880 --> 00:01:43,360 結果が新しいコレクションに集約されます。 30 00:01:43,520 --> 00:01:46,520 collect: に返される結果は 新しいコレクションです。 31 00:01:46,680 --> 00:01:50,160 ブロックがコレクションの各要素に 適用されています。 32 00:01:50,320 --> 00:01:53,800 2 の絶対値 -3 の絶対値つまり 3 33 00:01:53,960 --> 00:01:58,480 4 の絶対値の 4 -35 の絶対値の 35 34 00:01:58,640 --> 00:02:00,320 そして 4 の絶対値の 4 35 00:02:01,080 --> 00:02:04,200 覚えておいておくべきことは 36 00:02:04,360 --> 00:02:06,760 オブジェクトで考えるということです。 37 00:02:06,920 --> 00:02:09,720 コレクションに何かをするようにお願いします。 38 00:02:09,880 --> 00:02:14,440 コレクションは自分で その要素を列挙します。 39 00:02:14,600 --> 00:02:17,240 各要素への処理を与えます。 40 00:02:17,400 --> 00:02:20,400 これがイテレータの大事な部分です。 41 00:02:21,040 --> 00:02:23,280 これは collect: の別の例です。 42 00:02:23,440 --> 00:02:27,000 このコレクションに collect: メッセージを送ります。 43 00:02:27,160 --> 00:02:31,000 ブロックでは毎回 44 00:02:31,760 --> 00:02:34,200 要素が奇数か尋ねます。 45 00:02:34,360 --> 00:02:37,160 その結果を全て集約します。 46 00:02:37,320 --> 00:02:40,080 false、true、false、true、と。 47 00:02:43,720 --> 00:02:47,480 もちろん 48 00:02:47,640 --> 00:02:50,400 他の言語でやるように 49 00:02:50,560 --> 00:02:52,680 ブロックやイテレータを使わずに 書くこともできます。 50 00:02:52,840 --> 00:02:55,160 コレクションがあり 51 00:02:55,760 --> 00:02:58,680 結果のコレクションを作り 52 00:02:59,320 --> 00:03:03,560 1 から コレクションの大きさまで 整数を列挙します。 53 00:03:03,720 --> 00:03:04,960 to:do: を使います。 54 00:03:05,120 --> 00:03:08,920 コレクションを列挙して result コレクションに追加していきます。 55 00:03:09,080 --> 00:03:12,400 こうやって書くこともできます。 全く同じことです。 56 00:03:12,560 --> 00:03:15,440 あなた次第です。 シンプルに書きたいのか 57 00:03:15,600 --> 00:03:19,000 それとも、ややこしく書きたいか。 それだけの話です。 58 00:03:19,160 --> 00:03:22,000 私はシンプルなやり方のほうが断然良いです。 59 00:03:24,200 --> 00:03:27,120 Pharo のコレクションの階層では 60 00:03:28,320 --> 00:03:32,000 全てのコレクションは多相的で 61 00:03:32,160 --> 00:03:35,080 Collectionクラスを継承しています。 つまり、共通の API があります。 62 00:03:35,240 --> 00:03:39,720 長所として、大部分のコレクションで 63 00:03:39,880 --> 00:03:42,840 同じイテレータを使えます。 64 00:03:44,480 --> 00:03:48,080 それがオブジェクトで考えるということです。 65 00:03:48,240 --> 00:03:51,280 コレクションに 自分の中身を列挙するように言います。 66 00:03:51,440 --> 00:03:54,800 言った側は Dictionary(辞書)を 使っているのかどうかも、わかりません。 67 00:03:54,960 --> 00:03:58,880 我々はキーや値がどうしたという 内部的なロジックを知りたくはありません。 68 00:03:59,400 --> 00:04:02,320 だからコレクションに行儀よくお願いして 69 00:04:02,480 --> 00:04:04,960 その要素を処理してもらうのです。 70 00:04:06,640 --> 00:04:11,320 沢山のイテレータが使えます。 do: と collect: はもう見ましたね。 71 00:04:11,480 --> 00:04:14,280 他にももっとあります。 select:、 reject:、 detect:、などなど。 72 00:04:14,440 --> 00:04:17,840 このコースではそのうちいくつかを 後で学びます。 73 00:04:19,320 --> 00:04:22,760 do: は最も単純なイテレータです。 74 00:04:22,920 --> 00:04:26,960 do: はコレクションの各要素を列挙します。 トランスクリプトに表示します。 75 00:04:27,120 --> 00:04:30,560 もう何度も勉強しましたね。 76 00:04:30,720 --> 00:04:33,320 新しいイテレータがあります。select: です。 77 00:04:33,480 --> 00:04:36,560 コレクションの要素のうち 78 00:04:36,720 --> 00:04:38,360 条件に合ったもの全てを得ます。 79 00:04:38,520 --> 00:04:41,960 コレクションの要素のうち 奇数のものを得ます。 80 00:04:42,120 --> 00:04:45,040 このコレクションに select: を送ります。 81 00:04:45,200 --> 00:04:46,440 ブロックを渡します。 82 00:04:46,600 --> 00:04:49,560 ブロックの値が true であれば 83 00:04:49,720 --> 00:04:53,080 その要素は結果のコレクションに追加されます。 84 00:04:55,040 --> 00:04:58,080 select: #odd と全く同じです。 85 00:04:58,240 --> 00:05:01,120 ブロックの中で 86 00:05:01,280 --> 00:05:05,400 ブロックの引数に単項メッセージを 87 00:05:05,560 --> 00:05:06,920 送っているだけであれば 88 00:05:07,080 --> 00:05:10,760 メッセージの名前をシンボルとして 渡すことができます。 89 00:05:10,920 --> 00:05:12,480 このほうが、より短く書けます。 90 00:05:12,640 --> 00:05:16,000 単項メッセージしか使えません。 91 00:05:17,920 --> 00:05:20,880 他のイテレータとしては reject: があります。 92 00:05:21,040 --> 00:05:24,160 このコレクションの要素のうち 奇数のものを取り除いたものを得ます。 93 00:05:24,320 --> 00:05:27,520 結果として偶数のみが残っています。 94 00:05:28,520 --> 00:05:30,160 また、detect: もあります。 95 00:05:30,320 --> 00:05:34,000 条件に合う最初の要素を見つけます。 96 00:05:34,160 --> 00:05:37,000 つまりブロックの値が true になるものです。 97 00:05:37,160 --> 00:05:40,920 このコレクションの最初の奇数要素を得ます。 11 です。 98 00:05:42,320 --> 00:05:46,880 条件に合う最初の要素が欲しいわけですが 99 00:05:47,040 --> 00:05:50,120 条件に合うものが 1 つもない場合には デフォルトが欲しくなります。 100 00:05:50,280 --> 00:05:52,440 detect:ifNone: です。 101 00:05:52,600 --> 00:05:57,360 もし条件に合うものがなければ このブロックの値を返します。 102 00:05:57,520 --> 00:05:59,640 この場合、0 です。 103 00:05:59,800 --> 00:06:04,800 他にもプログラマを楽にしてくれる イテレータがあります。 104 00:06:04,960 --> 00:06:06,800 例えば、anySatisfy: です。 105 00:06:06,960 --> 00:06:10,600 条件に合う要素が 1 つでもあるか確認します。 106 00:06:10,760 --> 00:06:13,320 全ての要素が条件に合うか確認する ことができます。 107 00:06:13,480 --> 00:06:17,320 末尾から逆順にコレクションを列挙する ことができます。 108 00:06:17,480 --> 00:06:22,360 コレクションのインデックスと要素を列挙したり 要素を2つずつ列挙することもできます。 109 00:06:22,520 --> 00:06:26,480 要素から全ての順列を列挙することができます。 110 00:06:26,640 --> 00:06:28,960 沢山のイテレータがあります。 111 00:06:29,120 --> 00:06:31,480 新しいイテレータを作ることもできます。 112 00:06:31,640 --> 00:06:35,320 コレクション 1 2 3 を 113 00:06:35,480 --> 00:06:38,440 もう 1 つのコレクションと一緒に 列挙します。 114 00:06:38,600 --> 00:06:42,600 do: の引数のブロックには :x と :y の 2 つの引数があります。 115 00:06:42,760 --> 00:06:46,840 :x は1つ目のコレクションの要素 116 00:06:47,000 --> 00:06:48,920 :y は2つ目のコレクションの要素です。 117 00:06:49,080 --> 00:06:51,080 これらの要素を掛け算します。 118 00:06:51,240 --> 00:06:53,720 結果は 10、40、90 です。 119 00:06:54,840 --> 00:06:59,440 もちろん、このイテレータを使うには コレクションの長さが同じでなければなりません。 120 00:07:01,360 --> 00:07:04,720 他にもあります。 121 00:07:04,880 --> 00:07:08,120 ここでは do:separatedBy: を使っています。 122 00:07:08,280 --> 00:07:11,280 コレクションの各要素を列挙しますが 123 00:07:11,440 --> 00:07:14,040 1つの要素を挙げる毎に 124 00:07:14,200 --> 00:07:17,680 コンマを書き出すブロックを評価します。 125 00:07:17,840 --> 00:07:20,480 つまり、a を挙げて 126 00:07:20,640 --> 00:07:23,320 コンマを表示して、次に b で 次にコンマ、次に c となります。 127 00:07:23,480 --> 00:07:26,400 各要素の間に 1つのアクションを実行します。 128 00:07:28,880 --> 00:07:31,640 これは groupBy: イテレータです。 129 00:07:31,800 --> 00:07:36,040 コレクションの要素を条件に従って 130 00:07:36,200 --> 00:07:37,720 グループ分けします。 131 00:07:37,880 --> 00:07:42,040 コレクション 1 2 3 4 5 6 7 に このメッセージを送ります。 132 00:07:42,200 --> 00:07:45,480 結果として辞書が得られます。 133 00:07:47,000 --> 00:07:50,440 この #even という条件に対して 134 00:07:50,600 --> 00:07:52,800 false だった全ての要素がこれです。 135 00:07:52,960 --> 00:07:56,000 見ての通り 奇数の要素全てです。 136 00:07:56,160 --> 00:07:59,520 偶数の要素はすべて true を返します。 137 00:08:02,280 --> 00:08:04,520 よくあることですが 138 00:08:04,680 --> 00:08:07,720 コレクションの中にコレクションを 入れ子にしがちです。 139 00:08:07,880 --> 00:08:11,440 結果として深いレベルの入れ子になります。 140 00:08:11,600 --> 00:08:14,480 これは手で作った例ですが 141 00:08:14,640 --> 00:08:17,560 コレクションの中にコレクションが 入れ子になっています。 142 00:08:17,720 --> 00:08:22,200 このコレクションをフラットにします。 それぞれの要素を引っ張り出して。 143 00:08:22,880 --> 00:08:26,960 Pharo では簡単な方法があります。 144 00:08:27,120 --> 00:08:29,120 flatCollect: イテレータです。 145 00:08:29,280 --> 00:08:33,520 要素を列挙して 新しい平坦なコレクションを作ります。 146 00:08:35,240 --> 00:08:38,280 コレクション 1 2 3 4 5 6 が得られます。 147 00:08:38,440 --> 00:08:40,600 入れ子は無くなっています。 148 00:08:44,040 --> 00:08:48,520 Pharo の全てのイテレータについて 説明するつもりはありません。 149 00:08:48,680 --> 00:08:52,480 そんなことしたらダラダラと退屈なことになります。 ただ、沢山あるということはお見せしたいと思います。 150 00:08:52,640 --> 00:08:54,280 コレクションのクラスを読んで 151 00:08:54,440 --> 00:08:57,760 自分でイテレータを定義することができます。 152 00:08:57,920 --> 00:08:59,560 それを見てみましょう。 153 00:08:59,720 --> 00:09:02,960 とりあえず 既に知っているイテレータから出発します。 154 00:09:03,120 --> 00:09:05,840 do: はどうやって実装されているでしょうか? 155 00:09:06,000 --> 00:09:08,600 コレクションの階層で見てみましょう。 156 00:09:08,760 --> 00:09:13,760 SequenceableCollection に実装されています。 157 00:09:13,920 --> 00:09:16,680 do: メソッドは aBock を引数に取ります。 158 00:09:16,840 --> 00:09:19,400 Collectionで定義されているものを実装しています。 159 00:09:19,560 --> 00:09:23,320 1 to: self size do: [i:| aBlock 160 00:09:23,480 --> 00:09:26,600 引数として渡されたブロックに 161 00:09:26,760 --> 00:09:29,840 i 番目の要素を渡して評価します。 162 00:09:30,000 --> 00:09:31,160 とても簡単です。 163 00:09:31,960 --> 00:09:37,280 見てきた通り、Pharo では イテレータはとても強力です。 164 00:09:37,440 --> 00:09:41,880 各コレクションがイテレータを 多相的にサポートしています。 165 00:09:42,040 --> 00:09:45,200 プログラマは 166 00:09:45,360 --> 00:09:48,240 コレクションクラスで実装された イテレータを使うことで 167 00:09:49,000 --> 00:09:51,720 そのコレクションに従って 列挙することができます。 168 00:09:52,520 --> 00:09:55,200 新しいイテレータを定義することができます。 とても面白いです。 169 00:09:55,360 --> 00:09:58,840 コレクションクラスに自分のイテレータを 定義することができます。 170 00:10:00,480 --> 00:10:04,480 デザインパターンでのイテレータパターンを 知っている人には気になるかもしれませんが 171 00:10:05,160 --> 00:10:10,480 開発者はいつ次の要素を取り出すかを 決めることはできません。 172 00:10:10,640 --> 00:10:14,120 コレクションが内部でそれを決めます。 173 00:10:14,280 --> 00:10:17,160 next を直接イテレータに 送るのではありません。 174 00:10:17,320 --> 00:10:20,920 イテレータパターンを知っている人には 違和感があるかもしれません。 175 00:10:21,520 --> 00:10:25,720 イテレータはとても強力です。 176 00:10:25,880 --> 00:10:28,960 プログラマの最高の友達です。 177 00:10:29,120 --> 00:10:31,120 プログラムを書くことを簡単にします。 178 00:10:31,280 --> 00:10:34,280 コードを短く、簡潔に、エレガントに 書くことができます。 179 00:10:34,440 --> 00:10:37,320 コレクションの 180 00:10:37,960 --> 00:10:40,720 データのカプセル化を確保します。