Rubyの構造のつながりがわからないのだった


ぷわー、一気に難しくなった。やはり筑波大学の問題の23。5つの単語が最初に登録されていて、更に単語を入力すると記憶してくれる(pushのところ)。

tango = [“knowledge”, “information”, “system” , “library”, “metadata”]
while true
 print(“単語を入力してください\n”)
 print(“終わる時は . (ピリオド) を入力してください\n”)
 a = gets.chomp
 if a == “.”
  break
 end
 
 j=0
 while j < tango.size  if a == tango[j]   print(a, "は辞書に登録されています\n")   break  end    j=j+1  end    if j == tango.size   print(a, "を登録します\n")    tango.push(a)   end  end    tango.each{|value|   print(value, "\n")  }

最初に「j = 0」が立つことがピンと来ない。代入するための器としてまず0を入れておく、と考えればいいのかな?

「if a == tango[j]」の時はpushせずに「もう登録されているよ」ということで、breakして最初に戻る。

「j == tango.size」の時にpushできるというのがよくわからない。最初だったら「j=j+1」があるから、0+1で1の時tango.sizeと等しい、というのはどういう意味だろう。「j <= tango.size」だったら理解できるような気がする。そして「j <= tango.size」でも同じように動作しているみたいだ。謎。謎のまま次の問題に行こう。

コメント

  1. u-ki より:

    Rubyまったく知らないのですが、問題になってるのは、配列の要素番号は0から始まるということの理解にあるのでは?
    tango[0]=”knowledge”
    tango[1]=”information”
    tango[2]=”system”
    tango[3]=”library”
    tango[4]=”metadata”
    というふうに格納されます。0~4なので配列数(size)は5。
    どの言語でも0開始です。

  2. u-ki より:

    j=0
    配列の要素番号は0開始なのでこう宣言します。whileで操作するjの値を考えてみてください。
     while [0~4] < 5
     if a == tango[0~4]
      print(a, "は辞書に登録されています\n")
      break
     end
    既に登録済の配列[0~4]の内容チェックが終りました。全件合格だとjは最大値の4です。
    なので、
     j=4+1
     end
    配列のサイズは要素番号の最大値+1という調整をしています。なので、これをしないと
     if j == tango.size
    これは
     if j == tango.size-1
    と記述すると同じ動作が出来ます。
    配列サイズを基準に考えるとあまり美しくないですね。

  3. u-ki より:

    すみません、
    j=j+1
    しないと、while文が終りませんので
    なくしちゃダメですねw
    jの最大値をインクリメントした時に丁度配列サイズと同じになることを利用してるのですね。

  4. u-ki より:

    j+1が配列サイズの時、全件チェッククリア(同じ単語が登録済でない)なので初めてPushします。
    j=0~3の時はPushされませんで?

  5. u-ki より:

    すみません、嘘つきました。
    配列の添字、0から始まらない言語もあるみたいです。

  6. uporeke より:

    >>u-kiさん
    おお、いろいろ説明してくださってありがとうございます。

    なるほど、単語を追加した時に既存の4+新規1で5になるということなんですね。で、1つ追加したから次は6つチェックすることになる、と。すごく分かりやすいです。

    配列の最初が0というのは分かっているんですが、「j = 0」という条件を立てるというのが慣れていないせいで不自然に見えてしまうんですよね。関係ない(ように見える)jを立てるよりも、今ある配列からどうにかならないのか、と。そこは納得できるまでもう少し手を動かしてみます。

  7. u-ki より:

    同じ繰り返し文でも自分はfor文の方が好きなのですが、RubyだとJavaやCとは書き方違うのですね。
    配列操作のために要素番号をループカウンタで回す、というのはよくあることですし、繰り返し処理ではカウンタとしてiとかjは用意するもの、と捉えておくのがよろしいかと。

  8. はやし(哲) より:

    if tango.index(a) == nil
    print(a, “を登録します\n”)
    tango.push(a)
    else
    print(a, “は辞書に登録されています\n”)
    end

    で良いような気も。

    • uporeke より:

      >>はやし(哲)さん
      あー、ifで逆にしてもらうと分かったような気になります。
      英語順ぽくて。
      つまりはwhile文の条件を正確に把握していないということみたいなので、
      もうちょっと精進します。

  9. ac より:

    元ネタの23番ですが、Rubyの良い所が全部取り除かれた書き方ですね
    「繰り返し」セクションなのは分かりますが、if で出来るところは if で.. とも思います

    同じ物を書くならこんな感じとか?
    http://gyazo.com/5a133961563a9a6ad925145601c21224

    i j k みたいなカウンター変数も初心者用の参考書などでもよく見ますが、意味が分からない変数があると余計に分からなくなるのではと思います

    この筑波の問題はやればやるほどRubyが分からなくなってしまいませんか?

    • uporeke より:

      ac様
      コメント&サンプルを書いてくださってありがとうございます。
      カウンター変数はちょうど読み終えたアルゴリズムの初心者本でも出てきたので、
      避けては通れないものかと思っていました。
      if〜elseで書かれるとすごく分かりやすいですね(理解できているかは別なのですが…)

      筑波の問題は『たのしいRuby』と大分書き方が違うな、と思います。
      書き方を変えても動くところがプログラミングのおもしろさなのでしょうが……。