専門演習の紹介

広瀬研究室 / 神田研究室 / 西村研究室

その他の専門演習の先輩たちの話も聞こう。

繰り返しのまとめ

これまでは雛型や骨組 -- ものの捉えかたについて考えた。 計算機のプログラムは、 同じようなことを繰り返し何度も行なう場合に役に立つ。 プログラムは「もしこれが自動化されたらどうなるか」 を常に考えて作っている。この講義では行なわないが、 画像をプログラムと連係させたりする場合、 何と何が連動するのかを頭に入れておく必要がある。

回数を指定して繰り返すとき:

繰り返す整数.times do
実行すること 繰り返す整数値分繰り返される
end

大きな数から始めて、徐々に小さな数にする場合:

始める整数.downto(終りにする整数) do |変数|
変数の処理
end

小さな数から始めて、徐々に大きな数にする場合:

始める整数.upto(終りにする整数) do |変数|
変数の処理
end

始める数と終る数が決まっている場合:

for 変数 始める整数 .. 終りにする整数
変数の処理
end

配列の要素を調べたり変更するには

配列で method を知っていると、例えば、 ランキングなどの結果をきちんと対応させるときにも応用が効く。

配列の要素を調べて、順序を変えたり、 または外から持ってきた配列を結合したりすることができる。 配列 momo とする。

momo = [3, 4, 1, 2]

これをいろいろ操作して method の復習をしたい。

irb コマンドの起動

irb コマンドを起動してみよう。

%irb
irb(main):001:0>

irb の終了は exit である。

と出る。簡単な振舞いを調べるのに、 irb 内で全て調べを済ませることができる。

テストモデルの設定

momo の配列をしまおう。

%irb
irb(main):001:0> momo = [3, 4, 1, 2] 
=> [3, 4, 1, 2]

これで momo の配列を覚えた。

method を結合しよう

まずは前期で学んだ、 数字の若い順に並べ換える sort を使おう。


irb(main):002:0> momo.sort
=> [1, 2, 3, 4]

と、きちんと並べかえることができた。 以降いくつかまとめてみる。

配列に配列を結合するには

+ を使うと、別の配列 komomo を結合させることができる。 komomo = [6, 9, 8, 7, 0] を定義しよう。


irb(main):003:0> komomo = [6, 9, 8, 7, 0] 
=> [6, 9, 8, 7, 0]

komomo も定義し終ったので、 momo+komomo を実行しよう。


irb(main):004:0> momo + komomo
=> [3, 4, 1, 2, 6, 9, 8, 7, 0]

以降、 irb(main):開始行からの行数:0> を除いて表示していくことにする。 ここで、


irb(main):005:0> momo

irb(main):006:0> komomo

の 2 つを実行し、これらの中身は変化していないことに注意しよう。

<< "要素" とすると、もとの配列の最後の要素に新しい要素を付け加える。 momo5 を付け加えてみよう。


irb(main):007:0> momo << 5
=> [3, 4, 1, 2, 5]

momo が変更を受けた。


irb(main):008:0> momo

で確認しよう。

もとの配列に複数の要素を付け加えるには

もとの配列に複数の要素を付け加えるには push("値1", "値2", ...) を使う。また momo をもとの配列に定義し直して、5,9 を付け加えてみよう。


irb(main):009:0> momo = [3, 4, 1, 2]
=> [3, 4, 1, 2]

irb(main):010:0> momo.push(5, 9)
=> [3, 4, 1, 2, 5, 9]

また、文字列も一緒に扱うことができる。


irb(main):011:0> momo = [3, 4, 1, 2]
=> [3, 4, 1, 2]
irb(main):012:0> momo.push("mimi", "mumu")
=> [3, 4, 1, 2, "mimi", "mumu"]

である。

もとの配列に別の配列を付け加えるには

もとの配列の最後に別の配列を付け加えるには、 配列.concat(別の配列) とすればよい。 momokomomo を付け加えるには、


irb(main):013:0> momo = [3, 4, 1, 2]
=> [3, 4, 1, 2]
irb(main):014:0>komomo = [6, 9, 8, 7, 0]
=> [6, 9, 8, 7, 0] 
irb(main):015:0> momo.concat(komomo)
=> [3, 4, 1, 2, 6, 9, 8, 7, 0]

となる。komomo は変わらず、 komomo = [6, 9, 8, 7, 0] のままであることを確認せよ。

各要素 0 番目から最後まで 1 回ずつ使うには

each method を配列に使うことができた。 for 文では for i in 配列 -- 配列[i]の処理 -- end が使えたが、ここでは each で確かめておこう。 例えば momo の要素を足して行く場合、

momo = [3, 4, 1, 2] ならば
sum = 0
momo.each{|j|
    sum += j 
}
momo の 要素にある情報をそれぞれ each 取り出してはsum に足してゆけ

とすればよい。sum の答えは 10 を得る。

irb で実行して調べてみよう。

%irb
irb(main):001:0> momo = [3, 4, 1, 2]
=> [3, 4, 1, 2]
irb(main):002:0> sum = 0
=> 0
irb(main):003:0> momo.each{|j|
irb(main):004:1*  sum += j
irb(main):005:1>}
=> [3, 4, 1, 2]
irb(main):006:0> printf("%d\n",sum)
10
=> nil

逆順に配列するには

前期で学んだ reverse は逆順に並べるものであった。

momo = [3, 4, 1, 2] ならば reverse 後の配列 changed とすると

momo.reverse changed = [2, 1, 4, 3]
             momo = [3, 4, 1, 2] のまま

である。

逆順に配列し直すには

reverse! は破壊的 method (配列を変更してしまう method)である。 ! をつけると、 momo に method を作用させた結果を 上書き してしまう。


> momo = [3, 4, 1, 2]
=> [3, 4, 1, 2]
> momo.reverse!
=> [2, 1, 4, 3]
> momo
=> [2, 1, 4, 3]

momo が変化してしまった。上書きするような method を破壊的 method と呼ぶ。

要素がどこにあるのか調べるには

index(値) とすると、値にあるかどうか 0 番目の要素から調べ、 一番初めに発見した場所(添字番号)を返す。 見つからない場合は nil を返す。 momo = [3, 4, 1, 2] ならば


> momo.index(3)
=> 0

> momo.index(1)
=> 2
> momo.index(0)
=> nil

である。要素は 0 番目から始まることを思い出そう。 3 という値のある位置は momo[0] である。

最後にある要素を取り出すには

合計点などを最後の配列にしまっておいた場合、それを取り出すには、 pop を使う。


> momo
=> [3, 4, 1, 2]

> momo.pop
=> 2
> momo
=> [3, 4, 1]
> 

である。momo の最後の要素を取り出してきたが、そのかわり momo は一つ配列が短くなった。要素がない場合は nil を返す。 1 から 4 までのカードを持ってきて、シャッフルして並べた場合を配列で考えよう。 右から順に開いて行くのを表すのは 変数 card とすると、 card.rb

card = [3, 4, 1, 2]  ならば

while i = card.pop
printf("取り出した数は %d です\n", i)
end

とつくる。 card.pop により、数値は初めに 2、次に 1、その次に 4, 最後に 3 をとなる。計算が終ると card = [nil] となる。

最初にある要素を取り出すには

カードを左から順に取り出すときには shift が便利である。 これも、pop と同じように先頭要素を返したあと、配列を一つずつ縮めて行く。


> momo = [3, 4, 1, 2]
=> [3, 4, 1, 2]
> momo.pop
=> 2
> momo
=> [3, 4, 1]

である。繰り返していく場合には

card = [3, 4, 1, 2]  ならば

while i = card.shift
printf("取り出した数は %d です\n", i)
end

で、初めに 3、次に 4、その次に 1、最後に 2 となる。計算が終ると card = [nil] となる。

重複した要素を除くには

uniq で重複要素を取り除く。例えば

phone = [0, 2, 3, 4, 4, 1, 1, 1, 1, 1]ならば

changed = phone.uniq changed = [0, 2, 3, 4, 1]
                phone は変わらず
phone.uniq!     ならば phone = [0, 2, 3, 4, 1]

である。試してみよう。


> phone = [0, 2, 3, 4, 4, 1, 1, 1, 1, 1]
=> [0, 2, 3, 4, 4, 1, 1, 1, 1, 1]

> phone.uniq
=> [0, 2, 3, 4, 1]
> phone
=> [0, 2, 3, 4, 4, 1, 1, 1, 1, 1]
> phone.uniq!
=> [0, 2, 3, 4, 1]
> phone
=> [0, 2, 3, 4, 1]
! は破壊的 method を意味し、もとの定義を変更してしまう。

配列の数値を結合して文字列化するには

数値を計算した後に年月日にしたい場合などがある。 join("挟むのに使う文字") を用いると便利である。

 momo = [3, 4, 1, 2] ならば

momo.join("/")  文字列 "3/4/1/2" に変身
momo.join(", ") 文字列 "3, 4, 1, 2 " に変身
momo.join("$")  文字列 "3$4$1$2"に変身
momo.join       文字列 "3412" に変身         

である。

細かく指定して並べ替えするには

比較して並び換えをする演算子を使って、 sort をパワフルにすることができる。

<=>
比較して並び換えをする演算子 

A <=> B
A が B よりも小さかったら (A < B) 
A は B よりも先に決めておかなければならない
 {A => B}  
全て合わせて A <=> B   

これを用いて、sort{|調べたいブロックあるいは要素, 並べ換えをするために作られるブロックあるいは要素 | 並べ換えをするために作られるブロックあるいは要素 <=> 調べたいブロックあるいは要素}

とすると、並びかえができる。


> momo = [3, 4, 1, 2] 

> momo.sort{
* |momo,komomo| 
*  momo <=> komomo
>} 
[1,2,3,4]

momo.sort{             
  |momo,komomo|       
はじめにコピーされた komomo = [3, 4, 1, 2] が用意される momo <=>
momo と komomo を比較し komomo では順番を入れ替えていく
} 得られる changed = [1, 2, 3, 4]

である。文字列が入っていても同じである。

momo = [lolo, toto, pepe , kiki] のとき 
		      文字コード順では "k" < "l" < "p" < "t"

作ってみよう。

momo.sort{|momo,komomo| momo <=> komomo} 
 はじめにコピーされた
 komomo  = ["lala", "toto", "pepe", "kiki"] 
 が用意される。
 momo とコピーされた komomo について比較し
 komomo では順番を入れ替えていく
 changed = ["kiki", "lala", "pepe", "toto"]

である。調べておこう。


> momo = ["lala", "toto", "pepe", "kiki"]
=> ["lala", "toto", "pepe", "kiki"]
> momo.sort{|momo,komomo| momo <=> komomo}
=> ["kiki", "lala", "pepe", "toto"]

予想通り、アルファベット順に並べかえることができた。

簡単なプログラムについて

プログラムとして作り直しておこう。 各成分を表示する方法を見てみよう。 each_component.rb


momo = ["lala", "toto", "pepe", "kiki"] 

print("* * momo の要素 * *\n")
momo.each do |element|                 element は momo の要素を入れる変数 
printf("%s \n", element)
end print("* * momo の要素に bebe を追加 * *\n") momo << "bebe" momo.each do |element2| element2 は momo の要素を入れる変数
printf("%s \n", element2)
end printf("今の要素数は %d \n", momo.length) print("索引では \n") result = momo.sort while i = result.shift
printf("%s \n", i)
end

自分のプログラムの中で、起っていることがよく分らない場合、 動作の前後に上のように printfp または putsを使って調べるとよい。

配列の長さ(要素数)を返す

length(size でも同じ) を使うと、 配列の長さすなわち要素数がどれだけなのかがわかる。 momokomomo の配列の例では、


> momo = [3, 4, 1, 2]
=> [3, 4, 1, 2]
> komomo = [6, 9, 8, 7, 0] 
=> [6, 9, 8, 7, 0]
> momo.length
=> 4
> komomo.length
=> 5

である。

先頭に要素を追加するには

先頭に要素を追加するには、 unshift(値) を使うとよい。 unshift で入った要素が 0 番目になり、 もとの配列要素は 1 つずつずれる。


>momo.usnhift(5)
=> [5, 3, 4, 1, 2]

である。

配列の負の要素

momo = [3, 4, 1, 2]

のとき、momo[-1] は最後尾、momo[-2] は最後尾から 2 番目を指す。

> momo = [3,4,1,2]
=> [3, 4, 1, 2]
> momo[-1]
=> 2
> momo[-2]
=> 1