Search

検索したいワードを入力してください

2019年04月10日

Rubyでuntil文のループを使おう|基礎と応用的な使い方

Rubyには、untilという構文があります。これは、条件式を指定して、条件が真になるまで繰り返す構文です。Rubyの配列は、forやeachを使うよりも、untilを使う方が高速な場合がありますので、本記事では、こちらについても解説します。

untilとは

untilとは、条件式とブロックを指定して、指定された条件が真になるまで繰り返しを行います。このループ構文は、あらかじめ回数の決まっていないループを実行したいときに便利です。

while文との違い

untilは、whileとは対の関係にあります。while文では、条件が偽になるまで繰り返しますが、untilは逆に条件が真になるまで繰り返します。よって、until <条件式> はwhile!<条件式>とするのと同じで、while <条件式> はuntil !<条件式>とするのと同じです。

どちらを使用するかは、~である間、~でない間、~になるまで、~でなくなるまでというように、プログラム本来の意味合いによって使い分けるのが妥当です。

Rubyでのuntil文の基本な使い方

Rubyにおける、until文の使い方は以下の通りです。

until(<条件式>) do
<実行文>
end


条件式が最初から真である場合には、繰り返しは一度も実行されません。また、doの後に改行する場合は、そのdoを省略できます。

untilを使った作例

以下のRubyスクリプトでは、2のべき乗を1乗から順に求めています。べき乗した値が10の16乗(1京)を超えたらループを終了します。

n=1

until((p=2**n)>1e+16)
puts format"2^%2d = %16d (%2d桁)",n,p,p.to_s.length
n+=1
end

2^ 1 = 2 ( 1桁)
2^ 2 = 4 ( 1桁)
2^ 3 = 8 ( 1桁)
2^ 4 = 16 ( 2桁)
2^ 5 = 32 ( 2桁)
2^ 6 = 64 ( 2桁)
2^ 7 = 128 ( 3桁)
2^ 8 = 256 ( 3桁)
2^ 9 = 512 ( 3桁)
2^10 = 1024 ( 4桁)
2^11 = 2048 ( 4桁)
2^12 = 4096 ( 4桁)
2^13 = 8192 ( 4桁)
2^14 = 16384 ( 5桁)
2^15 = 32768 ( 5桁)
2^16 = 65536 ( 5桁)
2^17 = 131072 ( 6桁)
2^18 = 262144 ( 6桁)
2^19 = 524288 ( 6桁)
2^20 = 1048576 ( 7桁)
2^21 = 2097152 ( 7桁)
2^22 = 4194304 ( 7桁)
2^23 = 8388608 ( 7桁)
2^24 = 16777216 ( 8桁)
2^25 = 33554432 ( 8桁)

2^26 = 67108864 ( 8桁)
2^27 = 134217728 ( 9桁)
2^28 = 268435456 ( 9桁)
2^29 = 536870912 ( 9桁)
2^30 = 1073741824 (10桁)
2^31 = 2147483648 (10桁)
2^32 = 4294967296 (10桁)
2^33 = 8589934592 (10桁)
2^34 = 17179869184 (11桁)
2^35 = 34359738368 (11桁)
2^36 = 68719476736 (11桁)
2^37 = 137438953472 (12桁)
2^38 = 274877906944 (12桁)
2^39 = 549755813888 (12桁)

2^40 = 1099511627776 (13桁)
2^41 = 2199023255552 (13桁)
2^42 = 4398046511104 (13桁)
2^43 = 8796093022208 (13桁)
2^44 = 17592186044416 (14桁)
2^45 = 35184372088832 (14桁)
2^46 = 70368744177664 (14桁)
2^47 = 140737488355328 (15桁)
2^48 = 281474976710656 (15桁)
2^49 = 562949953421312 (15桁)
2^50 = 1125899906842624 (16桁)
2^51 = 2251799813685248 (16桁)
2^52 = 4503599627370496 (16桁)
2^53 = 9007199254740992 (16桁)

until文で無限ループする方法

untilは条件が真になったら終了するので、偽である間は繰り返すことになります。よって、until false do~endとすると、無限ループとなります。

無限ループのまま進まないスクリプトはバグですが、ブロック内に終了条件をつけたbreak文を入れることで、ループを終了することができます。無限ループを作成する方法には、他にもwhile true do~や、loop do~とする方法があります。

until false doで無限ループさせる

以下のRubyスクリプトでは、until false do~の無限ループを使って、入力された整数の合計を求めます。0が入力された時点でループから抜け、計算を終了します。

sum=0
cnt=1

puts"整数を入力(0で終了)"

until false do
begin
print"(%2d)> "%cnt
break if (n=Integer(gets))==0
sum+=n
cnt+=1
rescue
STDERR.puts"無効な入力です"
STDERR.puts
retry
end
end

puts
puts"合計: #{sum}"

実行例

整数を入力(0で終了)
( 1)> 645
( 2)> 315
( 3)> 579
( 4)> aaa
無効な入力です

( 4)> 154
( 5)> 972
( 6)>
無効な入力です

( 6)> 487
( 7)> 0

合計: 3152

until文で配列の値を取得する方法

C言語では、配列の値を取得するのにforを使ってループ変数を使います。Rubyにもfor文はありますが、C言語のforとは扱いが異なります。Rubyでは、until文を使うと、同じような条件のループを作成することができます。

RubyとC言語におけるforの違い

Rubyにおけるforは、配列などの各要素に、決まった回数のループを実行します。一方、C言語におけるforは、初期化式、継続条件式、再初期化式を指定して、継続条件式を満たさなくなるまで繰り返します。C言語のforと同じように扱えるループは、Rubyにおいてはwhile/untilを使うと可能です。

以下のRubyスクリプトでは、配列numsの合計を3通りの方法で求めています。

nums=[31, 82, 38, 58, 47, 77, 10, 80, 91, 50, 24, 97, 4, 33, 56, 51, 15, 90, 26, 37, 11, 40, 94, 63, 3, 88, 42, 67, 71, 19]

#for文を使う場合
sum=0
for num in nums
sum+=num
end
puts sum

#each文を使う場合
sum=0
nums.each do |num|
sum+=num
end
puts sum

#until文を使う場合(C言語のforと同じように使える)
sum=0
i=0
until i>=nums.length
sum+=nums[i]
end
puts sum

配列の各要素について処理する場合、untilを使うと外部でインデックス変数を定義しないといけないため、この方法はRubyにおいては望ましくありません。しかし、一部の要素に対して処理を行う場合には、untilを使った方が高速です。

untilを使って配列の要素を取得する

以下のRubyスクリプトでは、整数配列numsから、偶数インデックスの要素をnums_evenに代入しています。

nums=[31, 82, 38, 58, 47, 77, 10, 80, 91, 50, 24, 97, 4, 33, 56, 51, 15, 90, 26, 37, 11, 40, 94, 63, 3, 88, 42, 67, 71, 19]

nums_even=[]

i=0
until i>=nums.length
nums_even.push(nums[i])
i+=2
end

p nums_even

他の方法との速度を比較

同じ内容の処理を行う方法としては、each_with_indexメソッドや、select.with_indexを使う方法もあります。以下のRubyスクリプトでは、これらの2つの方法と、速度の比較を行います。バージョンはCygwinのruby 2.2.2p95です。

require"benchmark"

nums=(1..100_000_000).to_a

mtime=Benchmark.realtime do
nums.select.with_index{|num,i|i%2==0}
end
puts "%.3f(s)"%mtime #=> 15.161(s)

mtime=Benchmark.realtime do
nums_even=[]
nums.each_with_index do |num,i|
nums_even.push(num) if i%2==0
end
end
puts "%.3f(s)"%mtime #=> 16.689(s)

mtime=Benchmark.realtime do
nums_even=[]
i=0
until i>=nums.length
nums_even.push(nums[i])
i+=2
end
end
puts "%.3f(s)"%mtime #=> 5.452(s)

each_with_indexメソッドや、select.with_indexメソッドは、配列の要素すべてについて処理を実行を行うため、untilを使う方法より3倍近く時間がかかっています。

よって、一部の要素だけを処理したいときにはこれらの方法は適していません。untilは、すべての配列要素について処理を行う必要がないときに限って使うべきです。

until文は条件に応じて選択しよう

Rubyのループには、until文を使うべき条件があります。それは、以下の通りです。

(1)実行する前にループする回数が分からず、~するまで続けたいとき
(2)配列の一部の要素について処理するとき

配列のすべての要素についてインデックス付きで処理するには、each_with_indexを使うのが一般的です。この場合、外部でインデックス変数を定義する必要がなくなります。

【PR】多くの人がプログラミングを諦めてしまう理由をご存知ですか?



近年プログラミングを勉強する人が増えています。

プログラミング学習者の多くは独学から取り組もうとしますが、だいたい80%ほどは3ヶ月も続かずに諦めてしまいます。早い人は1日目で。

多くの人がプログラミングを独学しようとして諦める理由は、次の3つ。
●モチベーションが維持できない
●エラーの原因・解決方法が分からない
●どう学習すればよいか分からない

TechBoostというプログラミングスクールでは、みんなと一緒にプログラミングをするのでモチベーションの維持ができ、分からないことがあればマンツーマンで教えてくれ、徹底的に研究された初心者向けの教材が揃っています。

TechBoostを卒業後、実際にエンジニアとして転職した方もいるほど。

本気でプログラミングを学びたい方は、一度無料のカウンセリングでご相談ください。プログラミングを嫌いになる前に。

tech boostについて

オーダーメイド型の学習コンテンツを提供する「tech boost」 は、エンジニアのキャリア支援に特化したサービスを複数展開している株式会社Branding Engineerが運営しているプログラミングスクールです。最短3ヶ月間で、未経験から『プログラミングの基礎』、『実際に業務で必要となるスキル』、『今のトレンドとなっている知識』まで学べ、ご希望の方にはプロのキャリアアドバイザーによる就業支援を行うことができます。

tech boost卒業生インタビュー

tech boostの卒業生の声を聞きました。あなたがプログラミングを学びたい理由を、一度考えてみてください。
営業→Javaエンジニア→Rubyエンジニアと転向し、第一志望のFinTech企業で働く山下さん
元営業、ビジネスのわかるエンジニアを目指す菅原さん
サンフランシスコに交換留学し、シリコンバレーのVCでインターン中の梅本さん
予備校の営業から半年でエンジニア転職を果たした小田島さん

tech boostの口コミ



Related