value を使って並び換え

for 文を使うかわりに、 each 文を使ってもよい。


# 配列.each{                         # 第 0 要素から順に取り出して変数に代入
#      |配列の要素をしまう変数|      # 
#      配列の要素を使用して行う動作  #  
# }                                  #

例えば、pair.rb で、次のように書いてみよう。


shop.values.each{|item|                 # shop.values で value の並んだ配列
  printf("%s\t%d\n", item, shop[item])  # この配列の要素一つ一つを item に
}                                       # 代入する

keys method あるいは values method を使うと、 hash 配列に含まれる key や value を配列に埋め込む。

# p shop.values
p shop.keys

配列の入れ替えを行うには、sort method を使えば良かった。 reverse method も組み合わせて、 小さな順、大きな順ではそれぞれ以下のように並べ替えることができた。

p shop.values.sort
p shop.values.sort.reverse

その日の単価が最も高い穀物を割り出し、 Web で公告を出すように上司から頼まれている。 この性質を使って、ルビ緒は、 価格の入れ替えを行い価格の高いものをリストアップしながら出力するように、 プログラムを変更しようとを考えた。

print("本日の高値の穀物について\n")
p shop.values.sort.reverse.each{
|item|
    printf("%s\t%d\n", item, shop[item])
}

これでは結果を得られない。 shop.values.sort.reverse だけで得られる配列は確かに value の大きな順になっているが、 each method で指定したいものは hash 配列の key である。 shop.keys の配列が、 shop.values.sort の並べ替え順に並ぶようにしたい。 そこで、sort に詳しく指定をし、 value で入れ替えをするように、指定をすればよい。

# 配列.sort{
#   |もとの配列の要素を代入する変数,並べ替え後の配列要素を代入する変数|
#     もとの配列で並び替えに使用したい個所の指定 <=> 並べ替え後の該当個所
#      # 何を使って並べ替えるかを、
#      # もとの配列と並べ変え後の配列の要素を代入する変数を使って表す
#    }

もとの配列と並べ替え後の配列の要素を代入する変数は {} の中だけで使われるので、 適宜名前をつけ、使用してよい。 よって今の場合、これらの変数として prim, sorted を使うとすると、 prim, sorted は hash 配列 shop の key を担っており、 その value を使って入れ替えを行うことから、

shop.keys.sort{
   |prim,sorted|
   shop[prim] <=> shop[sorted]
}.reverse.each{

と変更すればよい。配列を詳しく入れ替えするときには

配列.sort{
   |A,B|
   配列[A] <=> 配列[B]

であった。今、Hash 配列.keys は配列であり、 配列の並びかえ要素は value = Hash 配列[key] である。 Hash 配列.keys の要素を代入する変数を A, B と取って実行する。 A, B は並びかえ前後の要素を区別するものである。

数値ではなく、 アルファベットを並び換えるとどうか。 また、ひらがなを並び換えるとどうか。 あるいは漢字を並べ変えるとどうか。 実際に簡単なプログラムを作成し、 漢字コードという言葉を使って結論を導け。

結局、価格の高い順に出力するには、

 
#!/usr/koeki/bin/ruby

shop = Hash.new("非取扱い商品")
print("本日の価格を入力してください\n")
print("** 入力は Ctrl-D\n")

while true
   STDERR.print("取扱商品名:")
   item = gets

   if item == nil                  # Ctrl-D が押されたら修了
     then break
   else
     item = item.chomp             # Ctrl-D 以外の文字列はここに進む
                                   # 改行文字を取れ
   end

   STDERR.print("100グラムあたりの価格:")

   price = gets.chomp.to_i  
   shop[item] = price
end

STDERR.print("入力終了 \n")

$KCODE = 'e'                   # 漢字コードは EUC で
#p shop                        # shop に入っているデータを全て見せよ

for item, price in shop do
  printf("%s\t%d\n", item, price)
end

print("本日の高値の穀物について\n")

shop.keys.sort{
  |prim,sorted|
  shop[prim] <=> shop[sorted]
}.reverse.each{
 |item|
  printf("%s\t%d\n", item, shop[item])
}

本日の講義 / 基礎プログラミング II / 2007 年度

Madoka Nishimura <madoka@e.koeki-u.ac.jp>