Hatena::Grouprubyist

krystal: プログラミング超初心者(文系)

2008-11-28 (Fri)たのしいRuby練習問題

P230 - num2astriskを定義しよう

19:12

  • "12"といった数値による文字列を、"************"というように、その数だけ「*」が並ぶ文字列に変換するメソッドnum2astriskを定義しよう。
  • ただし、Numericクラス(またはそのサブクラス)のオブジェクトやメソッドを使わないこと。
def num2astrisk(num)
  i = 1
  astrisk = "*"
  while i < num.to_i
    astrisk.concat("*")
    i += 1
  end
  return astrisk
end
p num2astrisk("10")  #=> "**********"

Stringクラスにも「+」があるから、セーフ?

parin30parin302008/11/29 13:33(*゚ー゚)これは駄目なのかにゃ?
"*" * num.to_i

rochefortrochefort2008/11/29 14:52↑すっきり!ですね。

rubyはカウンタ使わないでループ処理ができるので(イテレータ)
あえてそういう書き方をすると
こういう感じになりました。

def num2astrisk(num)
astrisk = "*"
out = ""
num.to_i.times{|x| out << astrisk}
out
end

prinypriny2008/11/29 17:35私も書いてみました。

def num2astrisk(num)
Array.new(num.to_i, "*").join
end

Numeric クラスのメソッドは使ってないと思う。
num.to_i がグレーなかんじ。
「最初から Numericクラス(またはそのサブクラス)の
オブジェクト」を使ってなければいいのかな?う~ん。

krystalkrystal2008/11/30 20:03>parin30さん
コメントをありがとうございます。
「*」はNumericではなくStringクラスやArrayクラスのメソッドでしたね。使えますね

>rochefortさん
コメントありがとうございます。
イテレータですね!
「ループ」を見るとついついwhileを使ってしまいます...

>prinyさん
コメントありがとうございます。
短いですね!
joinは文字列を返すメソッドでしたね。なるほどです。

holysugarholysugar2008/12/01 01:53ええと、問題の条件から、

1 は Numeric な Object なので、登場した時点でアウトでしょう。( 1.is_a? Numeric )
"1".to_i も 1 というオブジェクトを評価することになるので同様だと(自分は)思います。

ちゃんと題意に沿った方法があるので、もう少し探してみてはいかがでしょうか。

krystalkrystal2008/12/01 10:52>holysugarさん
コメントありがとうございます。
intにしたらアウトですか...
はい、もう少し考えてみます。

rubikitchrubikitch2008/12/01 12:28String#*は既出なので。

def num2astarisk(num)
("1"..num).map{"*"}.join
end
num2astarisk "4" # => "****"

krystalkrystal2008/12/01 19:17>rubikitchさん
コメントありがとうございます。
範囲オブジェクトは("1".."4")のようにも使えるんですね!知らなかったです。
数字とアルファベットにしか使えないと思ってました。

2008-11-27 (Thu)たのしいRuby練習問題

P203 - balanced?メソッドを定義しよう(再チャレンジ)

20:49

  • balanced?: (,),{,}という4つの文字を要素とした配列があります。この配列に対してかっこが正しく対応しているかどうかを調べるメソッド
  • 対応しているとは
    • (と)の数が同じ
    • {と}の数が同じ
    • 「()」の対応と「{}」の対応が交差することはない
  • 交差しているとは
    • ["(", "{", ")", "}"]というように、カッコの対応の中に別のカッコが片方だけ入り込んでしまっている場合を指します。
p balanced?(["(", "(", "{", "}", ")", ")"])
 #=> true
p balanced?(["(", "{", "{", "}", "(", "}", ")", ")"])
 #=> false

ヒントもらったので、もう一度

def balanced?(arr)
  a = arr.join(",").count("(")
  b = arr.join(",").count(")")
  c = arr.join(",").count("{")
  d = arr.join(",").count("}")
  array = []
  i = 0
  if a == b and c == d
    while i < arr.size
      case arr[i] 
      when "("
        array.push(arr[i])
      when "{"
        array.push(arr[i])
      when ")"
        prev = array.pop
        if prev != "("
          return false
        end
      when "}"
        prev = array.pop
        if prev != "{"
          return false
        end
      end
      i += 1
    end
    return true
  else
    return false
  end
end
p balanced?(["(", "(", ")", ")", "{", "}"])               #=> true
p balanced?(["(", "(", ")", ")", "{", "}", "{"])          #=> false
p balanced?(["(", "(", "{", ")", "}", ")"])               #=> false
p balanced?(["(", "(", "{", "{", "}", ")", "}", ")"])     #=> false

ポイントはスタックを使うこと。

push, pop, push, pop, push, pop ...


P230 - "七千百二十三"といった、漢数字による数の表現を「7123」のような数値に変換するメソッドkan2numを定義してみよう

20:49

def kan2num(kan)
  before_ten = kan.split(//s)[(kan.index("")/2 - 1)]

=begin
修正前のコードはこれ:
before_ten = kan.split(//s)[(kan.index("十") - 2)]
before_hundred = kan.split(//s)[(kan.index("百") - 2)]
before_thousand = kan.split(//s)[(kan.index("千") - 2)]

で、can't convert nil to string というエラーが出た
そこで p デバッグ!!

p kan.index("十")                         #=> これは正しかった
p kan.index("十") - 20                    #=> これも大丈夫だった
p kan.split(//s)[(kan.index("十") - 2)]   #=> nil
p kan.split(//s)                          #=> ここでkanを配列にしてしまってることがわかった。だからindexの数値にズレが生じた。
=end

  before_hundred = kan.split(//s)[(kan.index("")/2 - 1)]
  before_thousand = kan.split(//s)[(kan.index("")/2 - 1)]
  one_to_nine = "一二三四五六七八九"
  
  kan.split(//s).map {|change|
    case change
    when ""
      print 1
    when ""
      print 2
    when ""
      print 3
    when ""
      print 4
    when ""
      print 5
    when ""
      print 6
    when ""
      print 7
    when ""
      print 8
    when ""
      print 9
    when ""
      if one_to_nine.include?(before_ten) == false or kan.split(//s)[0] == ""
        print 1
      end
    when ""
      if one_to_nine.include?(before_hundred) == false or kan.split(//s)[0] == ""
        print 1
      end
    when ""
      if one_to_nine.include?(before_thousand) == false or kan.split(//s)[0] == ""
        print 1
      end
    end
  }

end
kan2num("三千百六十八")   #=> 3168
puts
kan2num("千四百七十一")   #=> 1471
puts
kan2num("九千五百十二")   #=> 9512

やはりエラーが出ると慌ててしまう。

追記:「0」のことを考えてなかった!"六千"とかは正しく表示されないね。。。


CD-ROM による正解はこれ

  • まだHashクラスの勉強に入ってないからHashを使ってないかも
  • だけど正規表現クラスの勉強にも入ってないのに、$1とか使ってる
  • これはよい正解なのか
def kan2num(string)
  digit4 = '0'
  digit3 = '0'
  digit2 = '0'
  digit1 = '0'
  
  nstring = string.dup
  nstring.gsub!(//,'1')
  nstring.gsub!(//,'2')
  nstring.gsub!(//,'3')
  nstring.gsub!(//,'4')
  nstring.gsub!(//,'5')
  nstring.gsub!(//,'6')
  nstring.gsub!(//,'7')
  nstring.gsub!(//,'8')
  nstring.gsub!(//,'9')

  if nstring =~ /((\d)?千)?((\d)?百)?((\d)?十)?(\d)?$/
    if $1
      digit4 = $2 || '1'
    end
    if $3
      digit3 = $4 || '1'
    end
    if $5
      digit2 = $6 || '1'
    end
    digit1 = $7 || '0'
  end
  return (digit4+digit3+digit2+digit1).to_i
end

if __FILE__ == $0
  print kan2num('七千百二十三'),"\n"
end

2008-11-20 (Thu)「たのしいRuby」練習問題

P203 - いろんな方法でsquareメソッドを定義しよう

20:05

  • square: 数値からなる配列numsに対して、その個々の要素の自乗した要素からなる配列を返すメソッド
p square([1,2,4,6]  #=>  [1,4,16,36])

まずは定義しないで作ってみる

num1 = [2,4,6]
num2 = []
num1.collect{|i|
  num2 << (i**=2)
}
p num2

collect!で定義してみる

def square(nums)
  nums.collect!{|i| 
    i **= 2
  }
end
p square([2,6,8])

collectで定義してみる

def square(nums)
  nums.collect{|i| 
    i **= 2
  }
end
p square([9,11,16])

eachで定義してみる

def square(nums)
  nums2 = Array.new
  nums.each{|i|
    nums2 << i **= 2
  }
  return nums2
end
p square([3,6,9,12])
p square([5,50,500])

collect, eachを使わず、インデックスと[]を使って定義してみる

def square(nums)
  nums2 = []
  i = 0
  while i < nums.size 
    nums2[i] = nums[i] ** 2
    i += 1
  end
  return nums2
end
p square([2,4,100])

**collect!で定義してみる」の部分を小見出しにしたかったのに、うえと合体されちゃった!記法通りにやってたのに、はてなバグ??

原因を教えてもらった!!

||<」の後ろにスペースが入ってたから -_-;

P203 - sum_arrayメソッドを定義してみよう

20:05

  • sum_array: 数値からなる配列nums1とnums2に対して、それらの個々の要素を足し合わせた要素からなる配列を返すメソッド
p sum_array([1,2,3], [4,6,8]  #=>  [5,8,11])

このように書いた

def sum_array(nums1, nums2)
  i = 0
  nums = []
  while i < nums1.size
    nums[i] = nums1[i] + nums2[i]
    i += 1
  end 
  return nums
end
p sum_array([1,2,3,9], [4,5,6,10])

P203 - balanced?メソッドを定義しよう

20:05

  • balanced?: (,),{,}という4つの文字を要素とした配列があります。この配列に対してかっこが正しく対応しているかどうかを調べるメソッド
  • 対応しているとは
    • (と)の数が同じ
    • {と}の数が同じ
    • 「()」の対応と「{}」の対応が交差することはない
  • 交差しているとは
    • ["(", "{", ")", "}"]というように、カッコの対応の中に別のカッコが片方だけ入り込んでしまっている場合を指します。
p balanced?(["(", "(", "{", "}", ")", ")"])
 #=> true
p balanced?(["(", "{", "{", "}", "(", "}", ")", ")"])
 #=> false
#これは交差のことを考慮してなかった
#数さえ合っていればよいと思ってた
def balanced?(arr)
  a = arr.join(",").count("(")
  b = arr.join(",").count(")")
  c = arr.join(",").count("{")
  d = arr.join(",").count("}")
  if a == b and c == d
    return true
  else
    return false
  end
end
p balanced?(["(", "(", ")", ")", "{", "}"])
p balanced?(["(", "(", ")", ")", "{", "}", "{"])

どうすれば交差しているかどうかを判断できるのか。

考え中...う~ん...

entottoentotto2008/11/21 11:46sum_array を zip, collect と inject を使って書いてみました。

def sum_array(arr, *rest)
arr.zip(*rest).collect do |each|
each.inject(0) {|memo,num| memo+num}
end
end

krystalkrystal2008/11/25 16:50> entottoさん
コメントありがとうございます。
いろいろ調べて、そのコードの意味を理解できました!

ちなみに、rochefortさんはentottoさんからヒントもらって、zipとmapのみで定義できたみたいですよ。
http://rubyist.g.hatena.ne.jp/rochefort/20081125

entottoentotto2008/11/26 13:51rochefort さんのは 2 つの配列を操作していて (仕様通り)、かつブロック引数を 2 つにすることで、足し算を inject ではなく普通にブロック引数に与えられた数字を足し合わせればいい書き方になっていますね。ブロック引数にそういう柔軟性があることは知りませんでした。

irb で試してみました:
irb(main):001:0> [[1,2]].each do |each| p each end
[1, 2]
=> [[1, 2]]
irb(main):002:0> [[1,2]].each do |a, b| p a,b end
1
2
=> [[1, 2]]
irb(main):003:0> [[1,2]].each do |*args| p args end
[[1, 2]]
=> [[1, 2]]

2008-11-18 (Tue)「たのしいRuby」練習問題

(修正)Page172 - 次のメソッドを持つクラス Celsius を定義する

17:50

# entottoさんから指摘を受けたので、修正。

class Celsius

  def initialize
  end
  
  def to_celsius(fahr)
    return 5 * (fahr - 32) / 9
  end

  def to_fahr(celsius)
    return 9 * celsius / 5 + 32
  end
  
  def +(cl)
    return self
  end
  
end
cel = Celsius.new
puts cel.to_celsius(100)
puts cel.to_fahr(38)
puts cel.+(20)
puts (cel.to_celsius(100).+(11))
puts (cel+20).is_a?(Celsius)

結果

37
100
#<Celsius:0x2bc3db8>
48
true

なぜ「puts cel.+(20)」の結果は「#<Celsius:0x2bc3db8>」?

selfを返してるから?

正解(from CD-ROM

class Celsius
  def initialize(celsius)
    @celsius = celsius
  end

  def to_celsius
    @celsius
  end

  def to_fahr
    (@celsius*9.0/5)+32
  end

  def +(other)
    @celsius += other
    self
  end

  def -(other)
    @celsius -= other
    self
  end

end

if __FILE__ == $0
  c1 = Celsius.new(30)
  c2 = c1 + 10
  p c2
  p c2.to_celsius
  p c2.to_fahr

  c2 = c1 - 10
  p c2
  p c2.to_celsius
  p c2.to_fahr
  
end

__FILE__ == $0 の意味が分からなくて調べてみたら、__FILE__ は実行中のプログラムのファイル名によると、以下のようにして書けば、ライブラリとして利用されるとき(require されて使われるとき)はサンプルコードの部分は実行されないそうだ。

if __FILE__ == $0
  # サンプルコード
end

P173 - 数値numが素数であるかどうかを調べるメソッドprime?(num)を定義する

17:50

def prime?(num)
  arr1 = []
  arr2 = []
  for i in 1...num+1
    div, mod = num.divmod(i)
#商をarr1に入れる
    arr1 << div
#余りをarr2に入れる
    arr2 << mod
  end
#  p arr1
#  p arr2
#numは2,3,5,7で割り切れない場合(余りは0じゃない場合)、素数だと判断
  case 
  when num == 2, num == 3, num == 5, num == 7
    p true
  when arr2[1] == 0, arr2[2] == 0, arr2[4] == 0, arr2[6] == 0
    p false
  else
    p true
  end
end
prime?(17)
prime?(10)
prime?(20)
prime?(29)
prime?(103)
prime?(66)
prime?(250)
prime?(2)

結果

true
false
false
true
true
false
false
true

これで大丈夫そう?

ややこしいけど。

正解(from CD-ROM)

まず効率が悪いやり方
def prime?(num)
  return false if num < 2
  (2...num).each{|i|
    if num % i == 0
      return false
    end
  }
  return true
end
そして、少し数学に明るい人が使うやり方
def prime?(num)
  return false if num < 2
  (2..Math::sqrt(num)).each{|i|
    if num % i == 0
      return false
    end
  }
  return true
end

HexaHexa2008/11/18 21:31仕様通りだと、下記のようになるのではないでしょうか。

Celsius.new(c) で摂氏の温度 c の値を持つインスタンスが作られます。
cel = Celsius.new(100)

Celsius#to_celsius で摂氏の温度 c がそのまま返ります。
cel.to_celsius
=> 100

Celsius#to_fahr で摂氏の温度 c を華氏の温度に変換した値が返ります。
cel.to_fahr
=> 212

Celsius#+(cl) で摂氏オブジェクトの足し算をおこなうので、
Celsiusオブジェクトは 2 つ必要ではないでしょうか。
cel1 = Celsius.new(10)
cel2 = Celsius.new(20)
(cel1 + cel2).is_a?(Celsius) => true
(cel1 + cel2).to_celsius => 86

krystalkrystal2008/11/19 18:03> Hexaさん
コメントありがとうございます。
著者による正解を↑に追加しました。
オブジェクトは2つでしたね。
ただ、c2 = c1 - 10 の場合、なぜ p c2 の結果は20ではなく、30だったかが分かりません。

tosiktosik2008/11/19 21:57口頭で説明しました。

そのコード↓

def +(other)
return Celsius.new(@celsius + other)
end

def -(other)
return Celsius.new(@celsius - other)
end

entottoentotto2008/11/20 10:29著者による正解では、Celsius.+ は破壊的メソッドでレシーバ自身の値が変わるという副作用があり、tosik さんのでは 非破壊的メソッドですね。
参考: Ruby FAQ::メソッド http://tinyurl.com/57fwoo

+ メソッドは大抵非破壊的な気がします。例)

irb(main):001:0> a = "ddd"
=> "ddd"
irb(main):002:0> a + "ccc"
=> "dddccc"
irb(main):003:0> a
=> "ddd" # a に + を送っても a の値は変わらない

メソッドを呼んだときにどういう副作用があるかがわかりやすいクラスを書くには、ruby の作法にのっとって Celsius なら Celsius.inc もしくは Celsius.+ (非破壊的)と Celsius.inc! (破壊的)の 2 つを用意するとよさそう。

krystalkrystal2008/11/21 12:13> tosikさん、entottoさん
コメントありがとうございます!
説明を受けて理解しました。
非破壊的なメソッドを使ったほうが混乱しなくなりそうなので、tosikさんが提示してくれたような方法を使おうと思います。
「+」の代わりに「increase」にするのもいいアイデアですね。

2008-11-17 (Mon)「たのしいRuby」練習問題

Page.172 - 華氏を摂氏に変換するメソッドを定義する

20:50

def fahr2celsius(fahr)
  5 * (fahr - 32) / 9
end
puts fahr2celsius(90)

結果

32

Page172 - 次のメソッドを持つクラス Celsius を定義する

20:50

  • 摂氏の温度cを持つインスタンスCelsius.new(c)
  • Celsius#to_celsius
  • Celsius#to_fahr
  • 摂氏オブジェクトclと足し算をして、新しい摂氏オブジェクトを返すCelsius#+(cl)
class Celsius
  def initialize(c)
    @c = c
    puts @c.to_s + ""
  end
  
  def to_celsius(fahr)
    @fahr = 5 * (fahr - 32) / 9
#   @fahr.to_s + "℃"
  end

  def to_fahr(celsius)
    @celsius = 9 * celsius / 5 + 32
#   @celsius.to_s + "°F"
  end
  
  def +(cl)
    @cl = @c + cl
#   @cl.to_s + "℃"
  end  
end

cel = Celsius.new(20)
puts cel.to_celsius(100)
puts cel.to_fahr(38)
puts cel.+(20)
puts (cel.to_celsius(100).+(11))

結果

20℃
37
100
40
48

entottoentotto2008/11/18 12:52Celsius#+(cl) の定義は「新しい摂氏オブジェクトを返す」なので、テストコードは (cel + 20).is_a? Celsius になるのでは。

あと、to_celsius, to_fahr, + で結果をインスタンス変数に入れていますが、値を返すだけなら不要だと思います。

2008-11-13 (Thu)練習:サイコロ / orange tree

サイコロ

20:25

cheatメソッドを書いて、サイコロの出る目をセットする

# DieはDiceの単数形
class Die
  def initialize
    roll
  end
  
  def roll
    @number_showing = 1 + rand(6)
  end
  
  def showing
    "The die shows " + @number_showing.to_s + "."
  end

#cheatを定義する。a~fを入力すると1~6を出す。
  def cheat
    @cheating = gets.chomp
    case @cheating
    when "a"
      puts "The die shows 1."
    when "b"
      puts "The die shows 2."
    when "c"
      puts "The die shows 3."
    when "d"
      puts "The die shows 4."
    when "e"
      puts "The die shows 5."
    when "f"
      puts "The die shows 6."
    else     
    puts Die.new.showing  #a~f以外の場合、showingを実行。
    end
  end
end

puts "Push any key to roll your die."
Die.new.cheat

間違ってるところがあれば突っ込んでください。

もっとよい方法、自然なやり方があれば、ぜひ教えてください。


Orange Tree

20:25

  • 毎年0.5mずつ成長する。ある年限が来たらその木は死んでしまう。
  • 3年は実をつけないが、その後は実がなる。で、成長した木は若い木よりたくさん実をつける。
  • オレンジをひとつ摘むと、@count_orangeが、1だけ小さくなり、
  • いかにおいしいオレンジだったかを告げる文字列かあるいは、
  • もう木にオレンジがなっていないことを告げる文字列かを返す。
  • ある年に取り残したオレンジは次の年には落ちてしまう。

class OrangeTree

  def initialize
    @height = 0
    @count_orange = 0
  end

  def height
    if @height >= 0
      if @height >= 5.0
        die
      else
        puts "The height of the orange tree now is " + @height.to_s + "m."
      end
    end
  end
  
  def one_year_passes
      @height += 0.5
  end
  
  def count_the_oranges
    
    case @height
    when 1.5
      @count_orange += 25
    when 2.0
      @count_orange += 30
    when 2.5, 3.0, 3.5, 4.0
      @count_orange += 40
    when 4.5, 5.0
      @count_orange += 50
    else
      puts "There is no orange on the tree."
    end
    if @count_orange == 0
      puts "There is no orange on the tree."
    else
      puts "There are " + @count_orange.to_s + " oranges on the tree."
    end
    @count_orange = 0
  end
  
  def pick_an_orange
    @count_orange -= 1
    puts "Yummy~~~!!!"
  end
  
  def die
    puts "The orange tree is dead."
    exit
  end
  
end

o = OrangeTree.new
o.one_year_passes
o.count_the_oranges
3.times do o.one_year_passes end
o.height
o.count_the_oranges
o.pick_an_orange
o.count_the_oranges
2.times do o.one_year_passes end
o.count_the_oranges
40.times do o.pick_an_orange end
o.count_the_oranges
3.times do o.one_year_passes end
o.count_the_oranges
3.times do o.one_year_passes end
o.height

結果

There is no orange on the tree.
There is no orange on the tree.
The height of the orange tree now is 2.0m.
There are 30 oranges on the tree.
Yummy~~~!!!
There are 29 oranges on the tree.
There are 40 oranges on the tree.
Yummy~~~!!!
Yummy~~~!!!
Yummy~~~!!!
Yummy~~~!!!
Yummy~~~!!!
Yummy~~~!!!
Yummy~~~!!!
Yummy~~~!!!
Yummy~~~!!!
Yummy~~~!!!
Yummy~~~!!!
Yummy~~~!!!
Yummy~~~!!!
Yummy~~~!!!
Yummy~~~!!!
Yummy~~~!!!
Yummy~~~!!!
Yummy~~~!!!
Yummy~~~!!!
Yummy~~~!!!
Yummy~~~!!!
Yummy~~~!!!
Yummy~~~!!!
Yummy~~~!!!
Yummy~~~!!!
Yummy~~~!!!
Yummy~~~!!!
Yummy~~~!!!
Yummy~~~!!!
Yummy~~~!!!
Yummy~~~!!!
Yummy~~~!!!
Yummy~~~!!!
Yummy~~~!!!
Yummy~~~!!!
Yummy~~~!!!
Yummy~~~!!!
Yummy~~~!!!
Yummy~~~!!!
Yummy~~~!!!
There is no orange on the tree.
There are 50 oranges on the tree.
The orange tree is dead.

2008-11-12 (Wed)練習

お題:

生まれた年、月、そして日を順に訊いてそこから年齢を計算します。

そして、過ごしてきた誕生日それぞれに対して大きなおめでとう!をプレゼントしましょう。

puts "生まれた年を入力してください。"
birth_year = gets.chomp
puts "生まれた月を入力してください。"
birth_month = gets.chomp
puts "最後に、生まれた日を入力してください。"
birth_day = gets.chomp

#years = Time.mktime(2008,11,11) - Time.mktime(birth_year.to_f, birth_month.to_f, birth_day.to_f)
#指摘を受けたので修正 → 特定の日ではなく現在の時刻から計算する。

years = Time.now - Time.mktime(birth_year.to_f, birth_month.to_f, birth_day.to_f)
one_year = 365*24*3600

mod = years
div, mod = mod.divmod(one_year)

i = 0
while i < div
  puts (i+1).to_s + " 才のお誕生日おめでとう!"
  i += 1
end

divmodを使ってみた。

entottoentotto2008/11/13 12:26スクリプト実行時点 (の実行マシンの時間) における年齢を計算するなら Time.mktime(2008,11,11) の代わりに Time.now で。

krystalkrystal2008/11/13 15:43> entottoさん
ご指摘、ありがとうございます。
修正しました。

2008-11-10 (Mon)練習

# 前回できなかった「0~100に含まれる0をカウントする」という問題を「0~1000に含まれる0をカウントする」に変更して修正。

arr = []

for i in 0..1000
  if /0/ =~ i.to_s
    arr << i
    if /00/ =~ i.to_s
      arr << i
      if /000/ =~ i.to_s
        arr << i
      end
    end
  end
end

p arr
puts arr.length

一応正しく動くけど、ifは3重になってる。う~ん...

HexaHexa2008/11/10 21:42case 文を使うと、整理できますよ。


count = 0

for i in 0..1000
case i.to_s
when /000/
count += 3
when /00/
count += 2
when /0/
count += 1
end
end

puts count

tosiktosik2008/11/11 01:34krystalさんの書き方だと、100 や 200 や 1000 が多重でカウントされてしまいますよ。
Hexaさんのだと多重にはカウントされませんね。

parin30parin302008/11/11 01:54Stringクラスのcountメソッド使うと短くできました^^

count = 0

for i in 0..1000
count += i.to_s.count("0")
end

puts count

entottoentotto2008/11/11 12:330自体の数をカウントしたいとき: /0/ でマッチすると、1010などの場合に 0 が 2 ではなく 1 とカウントされてしまい、1000以上の数に応用が効きません。
string.count を使うか、正規表現なら count=0; string.gsub(/0/) {|s| count+=1} とするか、かな?

krystalkrystal2008/11/11 16:22> Hexaさん
ありがとうございます。
確かに「ifが多くなるとcaseを使え」と達人に言われたことがあります^^


> tosikさん
そうですね、0がついてる数を配列に入れることでカウントしようとしました。
0が二つの場合は2回、三つの場合は3回入れて正しく出力させようとしました。
どろくさいですね。

> parin30さん
ありがとうございます。
Stringクラスのcountメソッド、知りませんでした!!
かなり短くなりましたね!

> entottoさん
.gsubのほうも試してみました。うまくできてるみたいです。
ありがとうございます!

yyamasakyyamasak2008/11/11 18:37蛇足ですが ('3')==3

(0..1000).inject(0){|c,i|c+i.to_s.count('0')}

krystalkrystal2008/11/11 19:16> yyamasakさん
ありがとうございます。
injectも初めて知りました!
1000以上の場合でも使えました^^v

ringo_ringo_2008/11/12 23:461000の次は、1000万まで、その次は1000兆まで と次の問いが続く

hh2008/11/13 14:31% ruby -e 'p (0..1000).to_a.join("").gsub(/[^0]/,"").size'

かな。

krystalkrystal2008/11/19 16:53> ringo_さん
コメントをありがとうございます。
試してみます。

> hさん
コメントをありがとうございます。
勉強になります。

2008-11-06 (Thu)Ruby写経+練習問題を解く

Ruby+プログラミング超初心者(文系)ということで、写経することから勉強します。

参考:プログラミング入門 - Rubyを使って -

8. メソッドの作り方

写経

def double_this(num)
  twice = num * 2
  puts num.to_s + " の 2 倍は " + twice.to_s + " です。"
end
double_this(33)
double_this(100)
puts twice.to_s  #twiceはローカル変数だから、メソッドの内部でしか(外からは)使えない。
def little_pest(var)
  var = nil
  puts "ハハ!お前の変数は破壊したぜ!"
end

var = "君はこの変数に手を触れることはできない!"
little_pest(var)
puts var
return_value = puts"この puts が返しているのは:"
puts return_value  #putsは常にnilを返す
def say_moo(num)
  puts "もぉ~~" * num
  "牛乳を飲もう~"
end

x = say_moo(2)
puts x
def ask(question)
  good_answer = false  
  while (not good_answer)
    puts question
    reply = gets.chomp.downcase
    
    if (reply == "yes" or reply == "no")
      good_answer = true
      if reply == "yes"
        answer = true
      else
        answer = false
      end
    else
      puts '"yes"か"no"かでお答えください。'
    end
  end
  
  answer
end

puts "こんにちは、私の実験のために..."
puts

ask "タコスは好きですか?"
ask "ブリートは好きですか?"
wets_bed = ask "ベッドを濡らしますか?"
ask "チミチャンガは好きですか?"
ask "タマーレは好きですか?"
puts "さらにいくつか質問を重ねます..."
ask "オルチャタを飲むのは好きですか?"
ask "フラウタスは好きですか?"

puts
puts "デブリーフィンブ:"
puts "ご協力感謝します..."
puts
puts wets_bed
def num_in_english(number)
  if number < 0
    return "負でない数を入力してください。"
  end
  if number == 0
    return "zero"
  end
  
  output = ""
  ones_place = ["one", "two", "three", "four", "five", "six", "seven", "eight", "nine"]
  tens_place = ["ten", "twenty", "thirty", "fourty", "fifty", "sixty", "seventy", "eighty", "ninety"]
  teenagers = ["eleven", "twelve", "thirteen", "fourteen", "fifteen", "sixteen", "seventeen", "eighteen", "nineteen"]
  
  remain = number
  write = remain/100
  remain = remain - write*100
  
  if write > 0
    hundred = num_in_english(write)
    output = output + hundred + " hundred"    
    if remain > 0
      output = output + " "
    end
  end
  
  write = remain/10
  remain = remain - write*10
  
  if write > 0
    if ((write == 1) and (remain > 0))
      output = output + teenagers[remain-1]
      remain = 0  #teenagersで1の位にも対応してくれるから1の位を出力させない。そうでないと、例)eleven oneになる。
    else
      output = output + tens_place[write-1]
    end
    if remain > 0
      output = output + " "
    end
  end
  
  write = remain
  remain = 0
  
  if write > 0
    output = output + ones_place[write-1]
  end
  output
end

puts num_in_english(0)
puts num_in_english(7)
puts num_in_english(11)
puts num_in_english(16)
puts num_in_english(34)
puts num_in_english(56)
puts num_in_english(88)
puts num_in_english(99)
puts num_in_english(100)
puts num_in_english(101)
puts num_in_english(234)
puts num_in_english(4634)
puts num_in_english(888888)
puts num_in_english(1000000000000)

練習

0-100までの数字を出力して、0何個あるかを数える。
i = 0
while i < 101
  puts i
  i += 1
end

arr = []
while /0|.0|.0.|..0/ =~ i.to_s #ここの問題か?
  arr << i
  i += 1
end

print "0の個数は:" + arr.length.to_s + "です。"

#値は合ってない。12のはずだが、なぜか10個しか出てこない。正規表現の使い方が間違ってる?
写経した「数字を英語発音にする」内容の改良
#ちゃんと表示されない数値いっぱいある
#重複が多い。うぅ!
def num_in_english(number)
  if number < 0
    return "負でない数を入力してください。"
  end
  if number == 0
    return "zero"
  end
  
  output = ""
  ones_place = ["one", "two", "three", "four", "five", "six", "seven", "eight", "nine"]
  tens_place = ["ten", "twenty", "thirty", "fourty", "fifty", "sixty", "seventy", "eighty", "ninety"]
  teenagers = ["eleven", "twelve", "thirteen", "fourteen", "fifteen", "sixteen", "seventeen", "eighteen", "nineteen"]
  
  remain = number
  write = remain/1000000
  remain = remain - write*1000000

  if write > 0
    output = output + ones_place[write-1] + " million"
    if remain > 0
      output = output + " "
    end
  end
  
  write = remain/1000
  remain = remain - write*1000

  if write > 0
    output = output + ones_place[write-1] + " thousand"
    if remain > 0
      output = output + " "
    end
  end
  
  write = remain/100
  remain = remain - write*100
  
  if write > 0
    output = output + ones_place[write-1] + " hundred"    
    if remain > 0
      output = output + " and "
    end
  end
  
  write = remain/10
  remain = remain - write*10
  
  if write > 0
    if ((write == 1) and (remain > 0))
      output = output + teenagers[remain-1]
      remain = 0  #teenagersで1の位にも対応してくれるから1の位を出力させない。そうでないと、例)eleven oneになる。
    else
      output = output + tens_place[write-1]
    end
    if remain > 0
      output = output + " "
    end
  end
  
  write = remain
  remain = 0
  
  if write > 0
    output = output + ones_place[write-1]
  end
  output
end

puts num_in_english(0)
puts num_in_english(7)
puts num_in_english(11)
puts num_in_english(16)
puts num_in_english(34)
puts num_in_english(56)
puts num_in_english(88)
puts num_in_english(99)
puts num_in_english(100)
puts num_in_english(101)
puts num_in_english(234)
puts num_in_english(4634)
puts num_in_english(8888)
puts num_in_english(6000000)

達人は短い行数で作れたのにな...

メソッドを作りましたっけ?

kalzekalze2008/11/07 19:28Ruby知らないのだけど。
練習「0-100までの数字を出力して、0何個あるかを数える。」のコメントに反応
arr = []
の後のwhileが全部意図したことと違うんじゃないかな
最初のwhileでiが1~100になってその間表示してる。
101になってwhile抜ける(初期化していないのでi=101)
で、次のwhileループ
101から110までは0が含まれるからwhileは真で、arrには101~110までの10個の数字が入っている
111になったときにwhileの条件式が偽になるので、while終了
なので最後は10になる

ちなみに、0の数ではなく、0が含まれる数の数だね(0の数というのであれば、100の時は2個とカウントすべき)

krystalkrystal2008/11/10 11:43kalzeさん、コメントありがとうございます!
本当ですね!
p arr
で見てみたら、中身は確かにそうなってました!

ちょっと修正しました。
>|ruby|
arr = []
for i in 0..100
if /0/ =~ i.to_s
arr << i
end
end
p arr
print arr.length
||<
しかしこれだと、0が含まれる数を数えることになるので、意図(0の個数を数えたい)と違います。
もうちょっと考えます。

krystalkrystal2008/11/10 11:45えっ!コメントでは「はてな記法」が使えないの~~~!?

rochefortrochefort2008/11/10 22:41re:数字を英語発音にする
やってみました。よかったらどうぞ。
http://rubyist.g.hatena.ne.jp/rochefort/20081109

krystalkrystal2008/11/11 15:30> rochefortさん
コメントありがとうございます!
では、そちらにお邪魔します^^