「たのしいRuby」 第11章 配列(Array)クラス

浅見れいなみたいな髪型にしたいなぁ、とか思っている26歳男子、bonlifeです。大好きなビンジョウバカネが活動停止ですって。あらまぁ…。ちょっぴり残念。今後はAPOGEEやらKOMEやらその他の道やらで活躍してくれることでしょう!ということで、私は勉強に励むことにします。早速、第11章の配列(Array)クラスの練習問題です。

ex11-1.rb

  • 1から100までの整数を含む配列を作る
ary = Array.new
100.times{|i|
  ary << i + 1
}

p ary

出力結果は以下の通り。

[1, 2, 3, 4, 5, 6, 7, 8, 9, 10, (中略) 91, 92, 93, 94, 95, 96, 97, 98, 99, 100]

解答例を見て気づいたことは以下の通り。

  • Rangeオブジェクトのto_aメソッドを使うとすごくシンプル

ex11-2.4b

  • (1)の配列の要素をすべて100倍した要素を含む新しい配列を作る
  • 新しい配列を作成せずに、すべての要素を100倍したものに置き換える
ary = Array.new
100.times{|i|
  ary << i + 1
}

ary100 = Array.new
ary.each{|i|
  ary100 << i * 100
}

p ary100
p ary

ary.collect!{|i|
  i * 100
}

p ary

出力結果は以下の通りです。

[100, 200, 300, 400, 500, (中略) 9600, 9700, 9800, 9900, 10000]
[1, 2, 3, 4, 5, (中略) 96, 97, 98, 99, 100]
[100, 200, 300, 400, 500, (中略) 9600, 9700, 9800, 9900, 10000]

解答例を見て気づいたことは以下の通り。

  • 素直にArray#collectを使うべき

ex11-3.rb

  • (1)の配列から3の倍数だけ取り出して、新しい配列を作る
  • 新しい配列を作成せずに、3の倍数以外の数を削除する
ary = Array.new
100.times{|i|
  ary << i + 1
}

ary.delete_if{|i|
  i % 3 != 0
}

p ary

出力結果は以下の通り。

[3, 6, 9, 12, 15, (中略) 87, 90, 93, 96, 99]

解答例を見て気づいたことは以下の通り。

  • 問題をちゃんと読んでおらず、1点目を完全に見落としてました…
  • 元の配列の一部から別の配列を作る場合はArray#selectを使う
  • Array#delete_ifではなくArray#reject!を使っても良い

ex11-4.rb

  • 配列を3つの方法で逆順に並べ替える
    • (a) Array#reverseメソッドを使う
    • (b) Array#sortメソッドを使う
    • (c) Array#sort_byメソッドを使う
ary = Array.new
100.times{|i|
  ary << i + 1
}

# (a) Array#reverseメソッドを使う

p ary.reverse

# (b) Array#sortメソッドを使う

p ary.sort{|a,b|
  b <=> a
}

# (c) Array#sort_byメソッドを使う

p ary.sort_by{|i|
  -i
}

出力結果は以下の通り。

[100, 99, 98, 97, 96, (中略) 5, 4, 3, 2, 1]
[100, 99, 98, 97, 96, (中略) 5, 4, 3, 2, 1]
[100, 99, 98, 97, 96, (中略) 5, 4, 3, 2, 1]

解答例を見て気づいたことは以下の通り。

  • (b)の比較ではブロックの結果を-1倍することによって、逆にソートしても良い

ex11-5.rb

  • (1)の配列に含まれる整数の和を次の2つの方法で求める
    • (a) Array#eachメソッドを使う
    • (b) Array#injectメソッドを使う
ary = Array.new
100.times{|i|
  ary << i + 1
}

# (a) Array#eachメソッドを使う

sum = 0
ary.each{|i|
  sum += i
}
p sum

# (b) Array#injectメソッドを使う

p ary.inject(initial=0){|sum,i|
  sum += i
}

出力結果は以下の通り。

5050
5050

解答例を見て気づいたことは以下の通り。

  • injectの引数に0を渡す場合、inject(0)とする

ex11-6.rb

  • randメソッドを利用して(1)の配列をでたらめな順番に並べ替える
ary = Array.new
100.times{|i|
  ary << i + 1
}

i = 0

ary.each{|i|
  ary.unshift(ary.slice!(rand(100)))
}

p ary

出力結果は以下の通り。

[75, 20, 1, 88, 86, (中略) 83, 84, 92, 96, 99]

解答例を見て気づいたことは以下の通り。

  • ブロックの中でrandでsort_byをすれば良い
    (正直、まだ仕組みを理解できていません…。)
  • 上記のやり方では配列の後半部分がでたらめにならない

ex11-7.rb

  • 1から100の要素を含む配列aryから、1〜10、11〜20というように10個の要素を含む配列を10個取り出し、そのすべての配列を別の配列resultに格納する
ary = Array.new
100.times{|i|
  ary << i + 1
}

result = Array.new
10.times{|i|
  result << ary[i*10,10]
}

p result

出力結果は以下の通り。

[[1, 2, 3, 4, 5, 6, 7, 8, 9, 10], [11, 12, 13, 14, 15, 16, 17, 18, 19, 20], (中略) [91, 92, 93, 94, 95, 96, 97, 98, 99, 100]]

解答例を見て気づいたことは特になし。同じ。
ex11-8.rb

  • 数値からなる配列nums1とnums2に対して、それらの個々の要素を足し合わせた要素からなる配列を返すメソッドsum_arrayを定義する
def sum_array(nums1,nums2)
  result = Array.new
  i = 0
  while i < nums1.length
    result << nums1[i]+nums2[i]
    i += 1
  end
  return result
end

p sum_array([1,2,3],[4,6,8])

出力結果は以下の通り。

[5, 8, 11]

解答例を見て気づいたことは以下の通り。

  • Array#zipを使うと便利 (配列の大きさを取得する必要なし)

ex11-9.rb

  • (,),{,}という4つの文字を要素とした配列に対して、カッコが正しく対応しているかどうかを調べるメソッドbalanced?メソッドを定義する
    • (と)の数が同じ
    • {と}の数が同じ
    • 「( )」の対応と「{ }」の対応が交差することはない
def balanced?(array)
  word_counts = Hash.new(0)
  array.each{|i|
    word_counts[i] += 1
  }
  if word_counts["("] != word_counts[")"]
    return false
  end
  if word_counts["{"] != word_counts["}"]
    return false
  end
  # 最初の値チェック
  if array[0] != "(" && array[0] != "{"
    return false
  end
  # 最後の値チェック
  if array[array.length-1] != ")" && array[array.length-1] != "}"
    return false
  end
  i = 0
  while i < array.length
    if array[i] == "(" && array[i+1] == "}"
      return false
    elsif array[i] == "{" && array[i+1] == ")"
      return false
    end
    i += 1
  end
  return true 
end

p balanced?(["(","{","{","}","(",")","}","(",")",")"])
p balanced?(["(","{","{","}","(","}",")",")"])
p balanced?([")","("])

出力結果は以下の通り。

true
false
false

解答例を見て気づいたことは以下の通り。

  • 上記のやり方は強引である上、空の配列が渡された場合、falseを返してしまう
  • 開き括弧に出会ったらをスタックに積んで、閉じ括弧に出会ったときに取り出しますやり方が妥当
    (スタックを使うんだろうな、と思いついたのですが、実装できませんでした…。)

6問目、消化できていませんよ…。sortの仕組みがいまいち飲み込めてません。また後でじっくり読んでみます。9問目の解き方はイメージは湧いたのですが、実装まで辿りつけませんでした…。ただ、Rubyの雰囲気はちょっとずつ分かってきた気がします。よくRubyはキレイなソースが書ける、と言われてますが、確かにPerlよりは読みやすくてスッキリしたソースが書けそうな雰囲気ですね。Rails勉強着手までの道のりはまだまだ続きます!