1

Rubyハッシュの自動活性化を実装するために、次のクラスを使用できます。

class AutoHash < Hash
  def initialize(*args)
    super()
    @update, @update_index = args[0][:update], args[0][:update_key] unless 
args.empty?
  end

  def [](k)
    if self.has_key?k
      super(k)
    else
      AutoHash.new(:update => self, :update_key => k)
    end
  end

  def []=(k, v)
    @update[@update_index] = self if @update and @update_index
    super
  end

  def few(n=0)
    Array.new(n) { AutoHash.new }
  end
end

このクラスでは、次のことができます

a = AutoHash.new
a[:a][:b] = 1
p a[:c] # => {}             # key :c has not been created
p a     # => {:a=>{:b=>1}}  # note, that it does not have key :c

a,b,c = AutoHash.new.few 3
b[:d] = 1
p [a,b,c] # => [{}, {:d=>1}, {}]  # hashes are independent

Joshuaによって提案されたこのクラスのもう少し高度な定義がありますが、これは私には理解するのが少し難しいです。

問題

新しいクラスを改善できると思う状況が1つあります。次のコードはエラーメッセージで失敗しますNoMethodError: undefined method '+' for {}:AutoHash

a = AutoHash.new
5.times { a[:sum] += 10 }

あなたはそれを処理するために何をしますか?[]+=演算子を定義できますか?


関連する質問

  1. PHPの場合と同様に、Rubyでも多次元ハッシュ配列の自動初期化は可能ですか?
  2. Rubyrubyハッシュ初期化rで新しい演算子を使用した自動活性化ハッシュの複数の初期化
  3. まだ開いています: Rubyでオブジェクトのディープコピー/クローン作成のための演算子を作成するにはどうすればよいですか?
4

3 に答える 3

5

[]+=rubyでメソッドを定義する方法はありません。入力するとどうなりますか

x[y] += z

x[y] = x[y] + z

したがって、メソッド[][]=メソッドの両方が呼び出されますx(そして、+で呼び出されます。x[y]この場合はAutoHash)です。+この問題を処理する最良の方法は、でメソッドを定義することだと思いますAutoHash。これは、引数を返すだけです。これは、AutoHash.new[:x] += yほぼすべてのタイプの、で機能します。これは、 (文字列、数値などの)プラスyの「空の」バージョンがほとんどの場合に等しいためです。y.class''0yy

class AutoHash
  def +(x); x; end
end

そのメソッドを追加すると、これらの両方が機能します。

# Numbers:
a = AutoHash.new
5.times { a[:sum] += 10 }
a[:sum] #=> 50

# Strings:
a = AutoHash.new
5.times { a[:sum] += 'a string ' }
a[:sum] #=> "a string a string a string a string a string "

ちなみに、これがあなたのコードのよりクリーンなバージョンです:

class AutoHash < Hash
  def initialize(args={})
    super
    @update, @update_index = args[:update], args[:update_key]
  end

  def [](k)
    if has_key? k
      super(k)
    else
      AutoHash.new :update => self, :update_key => k
    end
  end

  def []=(k, v)
    @update[@update_index] = self if @update and @update_index
    super
  end

  def +(x); x; end

  def self.few(n)
    Array.new(n) { AutoHash.new }
  end
end

:)

于 2010-07-03T19:05:28.043 に答える
1

私があなたが望むと思うのはこれです:

hash = Hash.new { |h, k| h[k] = 0 }

hash['foo'] += 3 # => 3

新しい値にはデフォルトで0が割り当てられているため、エラーなしで3、次に6などが返されます。

于 2015-02-05T01:05:55.803 に答える
0
require 'xkeys' # on rubygems.org

a = {}.extend XKeys::Hash
a[:a, :b] = 1
p a[:c] # => nil (key :c has not been created)
p a # => { :a => { :b => 1 } }

a.clear
5.times { a[:sum, :else => 0] += 10 }
p a # => { :sum => 50 }
于 2013-07-26T02:01:44.097 に答える