Ruby プログラミング

[Ruby]繰り返し処理

loop

こんにちは!じゃいごテックのあつしです。

今回はプログラミングの基本動作「逐次」「分岐」「反復」のうちのひとつ、反復(繰り返し処理)をご紹介します。
また、一緒に覚えておくと便利な機能についてもご紹介します。

決まった回数・範囲で繰り返す

timesメソッド

整数.times do |変数|
  処理
end

0 から指定した回数 - 1 までカウントアップしながら繰り返し処理を行います。変数は省略可能です。

# 0,1,2 とカウントアップしながら3回繰り返す
3.times do |n|
  p "Hello! #{n}"
end
# > "Hello! 0"
# > "Hello! 1"
# > "Hello! 2"

# こう書いても同じ
3.times { |n| p "Hello! #{n}"}
# > "Hello! 0"
# > "Hello! 1"
# > "Hello! 2"

# 変数は省略可
3.times { p "Hello!" }
# > "Hello!"
# > "Hello!"
# > "Hello!"
eachメソッド

繰り返しオブジェクト.each do |変数|
  処理
end

繰り返しオブジェクト先頭から次々に要素を参照して処理を行います。

# 範囲オブジェクトから要素を参照する
(0..2).each do |n|
  p "Hello! #{n} "
end
# > "Hello! 0"
# > "Hello! 1"
# > "Hello! 2"

# 配列から要素を参照する
["Taro", "Jiro", "Hanako"].each do |name|
  p "Hello! #{name}"
end
# > "Hello! Taro"
# > "Hello! Jiro"
# > "Hello! Hanako"
each_with_indexメソッド

繰り返しオブジェクト.each_with_index do |要素, インデックス|
  処理
end

繰り返しオブジェクトから要素とそのインデックスを取り出して繰り返し処理を行います。

# 範囲オブジェクトの要素とインデックスを同時に取り出す
("a".."e").each_with_index do |char, index|
  p "#{char},#{index}"
end
# > "a,0"
# > "b,1"
# > "c,2"
# > "d,3"
# > "e,4"
with_indexメソッド (each.with_index)

繰り返しオブジェクト.each.with_index(開始値) do |要素, インデックス|
  処理
end

繰り返しオブジェクトから要素と開始値からのインデックスを取り出して繰り返し処理を行います。

("a".."e").each.with_index(101) do |char, index|
  p "#{char},#{index}"
end
# > "a,101"
# > "b,102"
# > "c,103"
# > "d,104"
# > "e,105"
zipメソッド

繰り返しオブジェクト.zip(繰り返しオブジェクト,[繰り返しオブジェクト])

繰り返しオブジェクト自身と、引数で渡した配列の各要素を組にした配列を返します。
引数の要素数が多い場合は無視され、足りない場合は nil が代入されます。

name = ["Taro", "Jiro", "Hanako"]
age = [25, 22, 23]
hobby = ["fishing", "cycling", "piano"]
p name.zip(age, hobby)
# > [["Taro", 25, "fishing"], ["Jiro", 22, "cycling"], ["Hanako", 23, "piano"]]

条件を満たす間繰り返し続ける

while(制御構文)

while 条件式 do
  処理
end

条件式が true の間繰り返し処理を行います(doは省略可)。主に繰り返し回数が事前に分からない時に使用します。
繰り返しを終了するための条件を間違えると無限ループになる可能性があるので注意しましょう。【 強制終了: ctrl+C 】

# 0 から 9 までカウントする

count = 0
while count < 10
  p count
  count += 1
end
# > 0
# > 1
# > 2
# > 3
# > 4
# > 5
# > 6
# > 7
# > 8
# > 9

# この場合 count が 10 にならないので無限ループ
# 実行してみる場合は Ctrl + C で停止して下さい
count = 0
while count != 10
  p count
  count += 4
end
# > 0
# > 4
# > 8
# > 12
# > 16
# > 20, 24, ... 無限に続く

break・next

break(制御構文)

現在の繰り返し処理を脱出します。

# 0 から 9 まで表示するプログラムで
# カウント (n) が 3 になったら反復を脱出

(0..9).each do |n|
  break if n == 3
  p n
end
# > 0
# > 1
# > 2

n = 0
while n < 10
  break if n == 3
  p n
  n += 1
end
# > 0
# > 1
# > 2
next(制御構文)

以後の処理をスキップして、現在繰り返し中の次のステップの処理を行います。

# 0 から 9 の中で奇数を表示、偶数はスキップ

(0..9).each do |n|
  next if n.even?
  p n
end
# > 1
# > 3
# > 5
# > 7
# > 9

n = 0
while n < 10
  next if n.even?
  p n
  n += 1
end
# > 1
# > 3
# > 5
# > 7
# > 9

多重ループ

繰り返し処理の中に繰り返し処理を記述することを多重ループといいます。例えば2重ループで2次元配列、3重ループで3次元配列の全要素に次々とアクセスできます。

2重ループの例
ある中学校の各学年が3組ずつあるとして、1年1組から3年3組まで順番に出力してみる。

# 学年のループ
(1..3).each do |nen|
  # 組のループ
  (1..3).each do |kumi|
    p "#{nen}年#{kumi}組"
  end
end
# > "1年1組"
# > "1年2組"
# > "1年3組"
# > "2年1組"
# > "2年2組"
# > "2年3組"
# > "3年1組"
# > "3年2組"
# > "3年3組"
多重ループを使ってpaiza練習問題を解いてみる
かけ算表 (paizaランク D 相当)

※ paiza レベルアップ問題集 条件分岐メニューより

問題:

配列 A の要素数 N とその要素 A_i (1 ≦ i ≦ N) が与えられるので、A についてのかけ算表 B を出力してください。かけ算表は N * N の二次元配列の形式とし、B の i 行 j 列の要素 B_ij について、B_ij = Ai * Aj (1 ≦ i , j ≦ N) が成り立つものとします。

例として、A = [1,2,3] のとき B は

1 2 3
2 4 6
3 6 9

となります。

入力される値

N
A_1 ... A_N
  •  1 行目では配列 A の要素数 N が与えられます。
  •  2 行目では、A の各要素 A_i (1 ≦ i ≦ N) が半角スペース区切りで与えられます。

期待する出力

B_11 B_12 ... B_1N
...
B_N1 B_N2 ... B_NN

A のかけ算表 B を出力してください。

条件

すべてのテストケースにおいて、以下の条件をみたします。

  • 1 ≦ N ≦ 100 (1 ≦ i ≦ N)
  • 0 ≦ A_i ≦ 100 (1 ≦ i ≦ N)

入力例1
3
56 37 30
出力例1
3136 2072 1680
2072 1369 1110
1680 1110 900

入力例2
10
72 10 75 15 16 65 7 43 96 57
出力例2
5184 720 5400 1080 1152 4680 504 3096 6912 4104
720 100 750 150 160 650 70 430 960 570
5400 750 5625 1125 1200 4875 525 3225 7200 4275
1080 150 1125 225 240 975 105 645 1440 855
1152 160 1200 240 256 1040 112 688 1536 912
4680 650 4875 975 1040 4225 455 2795 6240 3705
504 70 525 105 112 455 49 301 672 399
3096 430 3225 645 688 2795 301 1849 4128 2451
6912 960 7200 1440 1536 6240 672 4128 9216 5472
4104 570 4275 855 912 3705 399 2451 5472 3249

解答例:

# 解答例1

# 要素数 n を整数で受け取る
n = gets.to_i
# 配列 A を受け取る(A -> ary とする)
ary = gets.split.map(&:to_i)

# 掛け算結果を格納する配列を用意する(n * n の二次元配列)
result = Array.new(n) { Array.new(n, nil) }

# 二重ループで掛け算を行う
n.times do |i|
  n.times do |j|
    result[i][j] = ary[i] * ary[j]
  end
end

# 掛け算の結果を表示する
result.each do |row|
  puts row.join(" ")
end

 

# [解答例2]

# 要素数 n を受け取る
n = gets.to_i
# 配列 A を受け取る(A -> ary とする)
ary = gets.split.map(&:to_i)

# 2重ループで要素を掛け算する
ary.each do |a|
  # 1 行分の計算結果を表示する
  puts ary.each.map { |b| a * b }.join(" ")
end

今回のまとめ

  • 決められた回数の繰り返しtimesメソッドeachメソッドを利用する
  • 条件を満たすまで繰り返すときは whileメソッドを利用する
  • 繰り返し処理の中に繰り返し処理を記述することで多重ループを作ることが出来る

今回紹介した以外にも繰り返しメソッドはありますが、times・each・while を覚えておけば大体対応出来ると思います!

paizaに2重ループの練習問題集がありますので、是非解いてみて下さい!

 

【PR】Ruby学習でお世話になった本




【PR】アルゴリズム学習でお世話になった本


アルゴリズム関連の技術書は大抵C/C++で書かれていますが、ある程度プログラムが出来れば、処理の流れは理解することが出来ます。






通称: 螺旋本。C++で解説されています。AOJ(Aizu Online Judge)を運営している会津大学の渡辺准教授が書いた本です。データ構造や計算量の内容から丁寧に書いてありますのでアルゴリズム学習の最初の参考書としてオススメです。







通称: 蟻本。C++で解説されています。競技プログラミング中級者の定番書と言われていて、競技プログラミングで利用できる色々なアルゴリズムを学ぶことが出来ます。かなり高度な内容も含まれているので1冊分を完全に理解するのにはかなりの時間がかかりそうですが、手元に置いて何度も読み返しています。







通称: チーター本。C#, C++, JAVAでTopcoderの問題を解説しています。初心者~中級者向けに書かれているので解説が非常に丁寧です。







Python3でアルゴリズムを解説している本です。講義スタイルの本で、図やフローチャートを使ってアルゴリズムとデータ構造についてしっかりと説明されています。代わりにコードは少なめです。Pythonコードが読めなくても十分理解できると思います。


-Ruby, プログラミング
-, , , , ,

© 2024 じゃいごテック