Ruby/Rails: Enumerable#map で時間を保持する Hash を作る

こんにちは、鈴木です。

 

Rails の View で時間を選択するプルダウンを作りたい場合には、collection_select などのメソッドを使用すると思います。

collection_select で使用する「時間を保持する Hash」ですが、どのように作りますか?

以下のような HOURS という Hash が定義されており、

View では次のように使用する想定です。

ここでの HOURS をどのように定義しますか、という話です。

 

愚直に書いてみる

試しに 愚直に書いてみます。

少しボリュームがありすぎる感じがします。

 

Enumerable#map と Hash[] を使う

Enumerable#map と Hash[] を組み合わせると、以下のように記述することができます。

1 行にまとまり、すっきりしました。

ポイントは (0..23) を map して、「[[0, '0時'], [1, '1時'], [2, '2時"], ..., [23, '23時']]」という配列を作成し、それを Hash[] に渡している点です。

 

分を保持する Hash

今度は「分」を保持する Hash を考えてみましょう。

以下のような 0 分から 59 分までの時間を保持する定数 MINUTES を初期化することを考えます。

やはり View で時間を選択するプルダウンを作るときに使用する想定です。

 

愚直に書いてみる(2)

とりあえず愚直に書いてみます。

時間(0〜23)よりも分(0〜59)の方が要素数が多いだけに、ぱっと見ただけで圧迫感があります。

 

Enumerable#map と Hash[] を使う(2)

時間を保持する Hash のときと同様に、Enumerable#map と Hash[] を使用してみましょう。

やはり 1 行にまとまり、非常にすっきりしました。

 

5 分間隔の分を保持する Hash

ちょっとした応用問題です。

先程は 1 分間隔の分を保持する Hash を作成しましたが、5 分間隔の場合はどうしますか?

この場合、(0..59) を map する前に、select で不要な要素を除外すれば OK です。

 

まとめ

普段 Ruby を使われている方にとっては簡単な内容だったかと思います。

一方で、冗長な書き方のせいで見づらくなっているソースコードを見ることもあります。

言語やフレームワークのレールに乗るための基礎体力が重要だなと思う今日このごろです。

 

Comments are closed, but you can leave a trackback: Trackback URL.

Comments

  • ブノア  On 2013年2月7日 at 08:56

    injectかeach_with_objectよりHash[Array]を使ってメリットありますか?スピードとか、メモリとか。

    • 鈴木 圭  On 2013年2月7日 at 10:28

      コメントありがとうございます。

      > injectかeach_with_objectよりHash[Array]を使ってメリットありますか?スピードとか、メモリとか。
      Hash[Array] が inject や each_with_object より優れている(もしくは劣っている)ということはありません。通常は読みやすいコードを書くべきなので、意図が伝わりやすい方法で Hash を構築すれば良いかと思います。

      ちなみにベンチマークを取ったところ、処理時間は以下のようになりました。(Ruby-1.9.3-p327 を使用、各100,000回実行した場合の処理時間)

      (1) Hash[Array] の場合 (処理時間: 12.569425)
      Hash[(0..59).map{|x| [x, sprintf('%d分', x)]}]

      (2) each_with_object (処理時間: 11.335173)
      (0..59).each_with_object({}){|i, map| map[i] = sprintf('%d分', i)}

      (3) inject (処理時間: 11.026367)
      (0..59).inject({}){|map, i| map[i] = sprintf('%d分', i); map}

      • ブノア  On 2013年2月7日 at 15:39

        了解です、ベンチマークまで書いてくださってありがとうございます。