モノノフ日記

普通の日記です

rubyチュートリアルを試してみる その3

id:Kiske:20070705:1183627478の続きです。7〜8章です。

プログラミング入門 - Rubyを使って -, by Chris Pine, 日本語ver. by S. Nishiyama

配列とイテレータ

配列と配列に関するメソッドの話です。ここはPHPとそんなに変わらない気がする。

練習問題
  • では、この章の最初で述べたプログラムを書いてみましょう。

ヒント: 配列を順番に並び替える(ソートする)には素敵なメソッド sortがあります。 これを使いましょう。(訳注:配列 ary の最後に要素 elem を追加するには、ary << elem と記述します。)最初で述べられてるプログラムは下記です。

好きな数だけ単語の入力をしてもらい(1行に1単語、最後はEnterだけの空行)、
アルファベット順に並べ変えて出力するようなプログラムを書いてみましょう
str = gets.chomp
array  = []
while str != ""
    array << str
    str = gets.chomp
end
puts 'ソート結果'
puts array.sort
  • 上のプログラムをsortメソッドなしで 書けますか。プログラミングの大部分は、問題解決にあります。これはいい練習になります。
str = gets.chomp
array  = []
while str != ""
    array << str
    str = gets.chomp
end
i = 0
while i < array.length
    j = i + 1
    while j < array.length
        if( array[i].to_s > array[j].to_s)
            tmp = array[i]
            array[i] = array[j]
            array[j] = tmp
        end
        j += 1
    end
    i += 1
end
puts 'ソート結果'
puts array

とりあえず単純なソートで実装してみました。ruby自体はどんな実装なんだろ。やっぱクイックソートなのかな

  • 以前、メソッドの章で書いた目次を表示するプログラムを修正してみましょう。
    その際、プログラムの最初で目次の情報(つまり、章の名前やページ番号など)をすべてひとつの配列にしまいます。
    その後、その配列から情報を取り出して美しくフォーマットされた目次を出力します。
lineWidth = 40
mokuji = []
title = '目次'
mokuji.push title
mokuji.push '1章: 数'.ljust(lineWidth) + 'p. 1'.ljust(lineWidth)
mokuji.push '2章: 文字'.ljust(lineWidth) + 'p. 72'.ljust(lineWidth)
mokuji.push '3章: 変数'.ljust(lineWidth) + 'p. 118'.ljust(lineWidth)
puts mokuji

メソッドの作り方

自作メソッドの作り方について解説されてます。PHPでいうfunctionです。
Rubyだとdef〜endで定義されます。

練習問題

・上のenglishNumberを拡張してみましょう。最初にthousand(千の桁)を導入してください。
上のプログラムでは 'ten hundred'となっているところを'one thousand'を返すように、あるいは、'one hundred hundred'の代わりに'ten thousand'を返すようにします。

def englishNumber number
  if number < 0
    return '負でない数を入力してください.'
  end
  if number == 0
    return 'zero'
  end

  numString = ''

  onesPlace = ['one', 'two', 'three', 'four', 'five', 'six', 'seven', 'eight', 'nine']
  tensPlace = ['ten', 'twenty', 'thirty', 'forty', 'fifty', 'sixty', 'seventy', 'eighty', 'ninety']
  teenagers = ['eleven', 'twelve', 'thirteen', 'fourteen', 'fifteen', 'sixteen', 'seventeen', 'eighteen', 'nineteen']

  left  = number
  ### 1000の位
  write = left / 1000
  left = left - write * 1000

  if write > 0
      thousands = englishNumber write
      numString = numString + thousands + ' thousand'
      if left > 0
          numString = numString + ' '
      end
  end

  write = left/100 
  left  = left - write*100

  if write > 0
    hundreds  = englishNumber write
    numString = numString + hundreds + ' hundred'
     if left > 0
      numString = numString + ' '
    end
  end

  write = left/10 
  left  = left - write*10

  if write > 0
    if ((write == 1) and (left > 0))
      numString = numString + teenagers[left-1]
      left = 0
    else
      numString = numString + tensPlace[write-1]
    end

    if left > 0
      numString = numString + '-'
    end
  end

  write = left
  left  = 0

  if write > 0
    numString = numString + onesPlace[write-1]
  end

  numString
end
  • englishNumberにさらに改良を加えましょう。 milion(百万)を加えます。
    その結果、'one thousand thousand'の代わりに 'one million'が得られるようにします。

その後、billion(十億)とかtrillion(兆)とかを追加していってみましょう。どこまでいけるでしょうか?

def englishNumber number
    if number < 0
        return '負でない数を入力してください.'
    end
    if number == 0
        return 'zero'
    end

    numString = ''

    onesPlace = ['one', 'two', 'three', 'four', 'five', 'six', 'seven', 'eight', 'nine']
    tensPlace = ['ten', 'twenty', 'thirty', 'forty', 'fifty', 'sixty', 'seventy', 'eighty', 'ninety']
    teenagers = ['eleven', 'twelve', 'thirteen', 'fourteen', 'fifteen', 'sixteen', 'seventeen', 'eighteen', 'nineteen']

    left = number

    digit_name = [' milion', ' thousand', ' hundred']
    digit_number = [1000000, 1000, 100]

    pointer = 0
    while pointer < digit_name.length
        write = left / digit_number[pointer]
        left = left - write * digit_number[pointer]

        if write > 0
            milion = englishNumber write
            numString = numString + milion + digit_name[pointer]
            if left > 0
                numString = numString + ' '
            end
        end
        pointer += 1
    end
    # 10の位
    write = left / 10
    left = left - write * 10

    if write > 0
        if( (write == 1) and (left > 0))
            numString = numString + teenagers[left-1]
            left = 0
        else
            numString = numString + tensPlace[write-1]
        end

        if left > 0
            numString = numString + '-'
        end
    end

    # 1の位
    write = left
    left = 0

    if write > 0
        numString = numString + onesPlace[write-1]
    end

    numString
end

100万、10億も1000と同じように追記できるので配列表記にして処理をひとまとめにしてみました。

  • weddingNumberはどうでしょう? このプログラムはenglishNumber とほとんど同じように動作しますが、"and" という接続詞をやたらめったら挿入します。

たとえば 'nineteen hundred and seventy and two' という具合に、結婚式の招待状のような感じで。
もう少し例を挙げたいと思いましたが、私自身詳しくありません。結婚のコーディネータに訊いてみるのも良いでしょう。

weddingNumberって何でしょう・・・?わからないので飛ばしました
  • "99本のビールが壁に..." englishNumberと以前作ったプログラムを使って、今度は正しい方法でこの歌の詩を出力させなさい。

その後は、9999から初めてコンピュータをこらしめましょう。 (ただ、あまり大きな数字を使うと、コンピュータといえども全部出力するのにかなりの時間を必要とします。
10万本のボトルには、かなりの時間がかかります。もし、100万本のボトルなどとするとあなた自身がひどい目に会いますよ。)

def singasong number
    while number > 0
        num = englishNumber(number)
        puts num + ' Bottles of beer on the wall'
        puts num + ' Bottles of beer'
        puts 'Take one down and pass it around'
        number -= 1
        puts englishNumber(number) + ' Bottles of beer on the wall'
    end
end

上で作ったenglishNumberを中で使ってますので動かすときはenglishNumberの定義も必要です。