1
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

Ruby で Hash#to_proc を使ってリストの要素に採番する

Posted at

Ruby でブロック付きメソッド呼び出しを省略する際、最後の引数に &obj という形で #to_proc を持つオブジェクトを指定する。

経験的にはメソッド名の Symbol を指定することが圧倒的に多く、時々 Method や Proc という感じがする。 Hash も #to_proc があるので指定できるけれども、使った覚えが無い。

Hash でなにか良い使い道が無いか考えたところ、リストの要素に番号(非負整数のID)を振って置換する際に便利そうだったのでやってみた。

コード

def ord() = Hash.new { |h, k| h[k] = h.size }

# 登場順に採番
p "abracadabra".each_char.map(&ord())
#=> [0, 1, 2, 0, 3, 0, 4, 0, 1, 2, 0]

# 小さい順に採番(座標圧縮)
ord_s = ord()
"mississippi".each_char.sort.each(&ord_s)
p "mississippi".each_char.map(&ord_s)
#=> [1, 0, 3, 3, 0, 3, 3, 0, 2, 2, 0]
p ord_s
#=> {"i"=>0, "m"=>1, "p"=>2, "s"=>3}

ord() は書かなくてもいいが、メソッドと変数を区別しやすいよう明示している

仕組み

リストの各要素について Hash のキーに対応する値を参照する場合は、わざわざブロックを書かなくても &obj で済む。

h = {1 => 10, 2 => 20, 3 => 30}
seq = [1, 2, 3]

# これらは同じ
seq.map { |elem| h[elem] }
seq.map(&h)

今回の用途では「 Hash にキーが無ければ生成・保存する」という処理を追加している。

seq.map do |elem|
  h[elem] = elem * 10 unless h.key?(elem)
  h[elem]
end

これは Hash に default_proc を設定しておくことでブロックから追い出せる。(別のブロックを書くことにはなるが)

h.default_proc = ->(hash, key) { hash[key] = key * 10 }
seq.map do |elem|
  h[elem]
end

採番については、ゼロ始まりとしておけば 採番済みの要素数 == 次の採番の番号 になるため、 Hash#size で次の番号を作成できる。

おまけ

同じ考え方によって、即席のメモ化にも使える。コード長については普通に書いたほうが短いが、 Hash を外部の変数に用意せず使い捨てできる長所はある。

# 毎回 to_i を実行する
p "abracadabra".each_char.map { |s| s.to_i(36) }
#=> [10, 11, 27, 10, 12, 10, 13, 10, 11, 27, 10]

# 一度 to_i を実行した要素については、キャッシュした結果を返す
h = {}
p "abracadabra".each_char.map { |s| h[s] ||= s.to_i(36) }

# Hash をその場で作れば、キャッシュは使い捨てになる
p "abracadabra".each_char.map(&Hash.new { |h, s| h[s] = s.to_i(36) })
1
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?