2017-01-13 25 views
1

これは簡単ですが、適切な解決策を見つけることができませんでした。Rubyハッシュでネストされたキーの動的な値を設定するには

resource.public_send("#{key}=", value) 

しかしfoo.bar.lolo用:最初のレベルのキーの ?

私は次のようにそれを得ることができることを知っている:

'foo.bar.lolo'.split('.').inject(resource, :send) 

または

resource.instance_eval("foo.bar.lolo") 

が、どのように私は入れ子のレベルを知っていないと仮定して、最後の変数に値を設定しますそれは第2または第3であってもよい。

すべてのレベルでそれを行う一般的な方法はありますか?私の例のための は、私は次のようにそれを行うことができます:Rubyで

resource.public_send("fofo").public_send("bar").public_send("lolo=", value) 
+0

'resource.public_send("#{key} = "、value)'はハッシュに何も設定しません。 – mudasobwa

+0

いいえオブジェクトが内部にあるネストされたキーでは機能しません。 'obj.fofo'でも動作しますが、' bject.fofo.lolo'では動作しません。未定義のメソッドを提供します – user181452

+0

批評だけでなく、事実や情報を書いてください:)それはウェブサイトのポイントです。あなたは知っているし、私は知らない。私の間違いを教えてください、それはちょうどこれを完全に役に立たないコメントを与えるよりも良い方法です。私はそれで何もできません。 – user181452

答えて

3

回答:あなたは物事にあなたがそれらを今セットアップされている方法を行うにはいくつかのメソッドを実装することもできますが

hash = { a: { b: { c: 1 } } } 
def deep_set(hash, value, *keys) 
    keys[0...-1].inject(hash) do |acc, h| 
    acc.public_send(:[], h) 
    end.public_send(:[]=, keys.last, value) 
end 

deep_set(hash, 42, :a, :b, :c) 
#⇒ 42 
hash 
#⇒ { a: { b: { c: 42 } } } 
+0

これは基本的にhash#bururyと同じではありませんか?すなわち[this](https://github.com/dam13n/ruby-bury) –

+0

@maxple私は '埋葬 'が何であるか分かりません。これは純粋なルビーです。 – mudasobwa

+0

それは掘るのに付随するようです。私はリンクされた宝石のように。ちょうど人々がこの機能を埋もれていると呼んでいる。 –

0

ハッシュは、デフォルトでは、あなたにこれらのドットメソッドを与えることはありません。

あなたが連鎖(これは任意のオブジェクト上で動作しますが、あなたは通常、このような方法でハッシュキーにアクセスすることはできません)の呼び出しを送信することができます

"foo".send(:downcase).send(:upcase) 

ネストされたハッシュを扱う可変性のトリッキーな概念が関連しています。例えば:ここ

hash = { a: { b: { c: 1 } } } 
    nested = hash[:a][:b] 
    nested[:b] = 2 
    hash 
    # => { a: { b: { c: 2 } } 

「可変性は、」あなたが別の変数にネストされたハッシュを保存するとき、それは実際にはまだ、元のハッシュへのポインタだということを意味します。このような状況では、Mutabilityは役に立ちますが、理解できない場合はバグが発生する可能性があります。

ある意味では、:aまたは:bを変数に割り当てて「動的」にすることができます。

などとしてこれを行うには、より高度な方法は、あなたがOpenStructを使用している場合、あなたはあなたのハッシュドット方式のアクセサを与えることができます

versions. 

    hash = { a: { b: { c: 1 } } } 
    keys_to_get_nested_hash = [:a, :b] 
    nested_hash = hash.dig *keys_to_get_nested_hash 
    nested_hash[:c] = 2 
    hash 
    # => { a: { b: { c: 2 } } } 

新しいRubyであります。正直にチェーンsendを呼び出すことは私が頻繁に使用したものではありません。コードを書くのに役立つなら、それは素晴らしいことです。しかし、ユーザー生成の入力を送信するべきではありません。なぜなら、それは安全ではないからです。ただ好奇心のうちハッシュのための

+2

'hash.public_send(:[]、:a).public_send(:[] =、:b、42)'完璧に動作し、何もトリッキーはありません。 – mudasobwa

0

が、私は強く、あなたのデータを再検討することをお勧めします構造。

用語の一部を明確にするために、例のkeyはキーではなくメソッド呼び出しです。 Rubyでは、my_thing.my_other_thingのようなコードがある場合、my_other_thingは常にメソッドであり、少なくとも適切な意味ではキーではありません。

この方法でオブジェクトを連鎖させることでハッシュのような構造を作成できますが、実際のコードの匂いがあります。foo.bar.loloをネストされたloloキーをハッシュで検索する方法であると考えると、通常のハッシュを使用しているはずです。

x = {foo: {bar: 'lolo'}} 
x[:foo][:bar] # => 'lolo' 
x[:foo][:bar] = 'new_value' # => 'new_value' 

がsend/instance_evalをメソッドはこの方法を使用することができる。また、それはベストプラクティスではありません、さらにはセキュリティ上の問題を作成することができます。

関連する問題