が定義されているかどうかを判断する最も簡潔な方法は何ですか?それは、またはnil@hash[:key1][:key2]
の場合にエラーをスローしませんか?@hash
@hash[:key1]
defined?(@hash[:key1][:key2])
存在する場合はTrueを返します(定義され@hash[:key1]
ているかどうかは判別しません):key2
が定義されているかどうかを判断する最も簡潔な方法は何ですか?それは、またはnil@hash[:key1][:key2]
の場合にエラーをスローしませんか?@hash
@hash[:key1]
defined?(@hash[:key1][:key2])
存在する場合はTrueを返します(定義され@hash[:key1]
ているかどうかは判別しません):key2
ActiveSupport (Rails) または Backports を使用する場合、以下を使用できますtry
。
@hash[:key1].try(:fetch, :key2)
@hash
次のことを処理することもできますnil
。
@hash.try(:fetch, :key1).try(:fetch, :key2)
@hash
不足しているキーのハッシュを常に返したい場合:
@hash = Hash.new { |h,k| h[k] = {} }
@hash[:foo] # => {}
この再帰を定義することもできます:
def recursive_hash
Hash.new { |h,k| h[k] = recursive_hash }
end
@hash = recursive_hash
@hash[:foo][:bar][:blah] = 10
@hash # => {:foo => {:bar => {:blah => 10}}}
しかし、あなたの質問に答えるには:
module HasNestedKey
Hash.send(:include, self)
def has_nested_key?(*args)
return false unless sub = self[args.shift]
return true if args.empty?
sub.respond_to?(:has_nested_key?) and sub.has_nested_key?(*args)
end
end
@hash.has_nested_key? :key1, :key2
おそらく私は何かが欠けているかもしれませんが、あなたが気にかけているのが簡潔であるなら...理由はありません:
@hash && @hash[:key1] && @hash[:key1][:key2]
または、数文字を保存したい場合
@hash && (h = @hash[:key1]) && h[:key2]
これのいずれかの部分が失敗した場合、それ以外の場合はまたはnil
に関連付けられた値を返します。:key2
true
defined?
存在しない場合でも true を返す理由は、:key2
参照しているオブジェクトが存在するかどうかをチェックするためです。その場合、ハッシュに存在する[]
メソッドのエイリアスであるメソッドですが、nil を返す場合の場合、fetch メソッドがなく、が返されます。そうは言っても、埋め込まれたハッシュを深く掘り下げる必要がある場合、ある時点で次のように呼び出す方が効率的になります。fetch
@hash[:key1]
nil
nil
n
defined?(@hash[:key1][:key2][:key3]) && @hash[:key1][:key2][:key3]
Hash#fetch の使用
Hash#fetchメソッドをデフォルトで使用できるため、最初のレベルのキーが存在しない場合でも{}
安全に呼び出すことができます。has_key?
例えば
!hash.nil? && hash.fetch(key1, {}).has_key?(key2)
別
または、条件演算子を使用することもできます。
!hash.nil? && (hash.has_key?(key1) ? hash[key1].has_key?(key2) : false)
つまり、キーがない場合hash
は、第 2 レベルのキーを検索せずkey1
に単に戻ります。false
存在する場合は、 の値をkey1
チェックした結果を返します。key1's
key2
また、呼び出す前にhash[key1]'s
値にメソッドがあることを確認する場合は、次のようにします。has_key?
!hash.nil? && (hash.has_key?(key1) ? hash[key1].respond_to?(:has_key?) &&
hash[key1].has_key?(key2) : false)
@hash[:key1].has_key? :key2
私が発見したもう1つのオプションは、seek
メソッドを使用してHashを拡張することです。テクニックはCoreyO'Danielから来ています。
これをイニシャライザーに貼り付けます。
class Hash
def seek(*_keys_)
last_level = self
sought_value = nil
_keys_.each_with_index do |_key_, _idx_|
if last_level.is_a?(Hash) && last_level.has_key?(_key_)
if _idx_ + 1 == _keys_.length
sought_value = last_level[_key_]
else
last_level = last_level[_key_]
end
else
break
end
end
sought_value
end
end
次に、電話するだけです。
@key_i_need = @hash.seek :one, :two, :three
値を取得します。存在しない場合はnilを取得します。
@hash[:key1][:key2]
(3 つのレベルのいずれかで)存在しないものと を区別することを気にしない場合@hash[:key1][:key2] == nil
、これは非常にクリーンで、任意の深さで機能します。
[:key1,:key2].inject(hash){|h,k| h && h[k]}
nil
既存のものとして扱いたい場合は、代わりにこれを使用します。
(hash[:key1].has_key?(:key2) rescue false)