3

が定義されているかどうかを判断する最も簡潔な方法は何ですか?それは、またはnil@hash[:key1][:key2]の場合にエラーをスローしませんか?@hash@hash[:key1]

defined?(@hash[:key1][:key2])存在する場合はTrueを返します(定義され@hash[:key1]ているかどうかは判別しません):key2

4

6 に答える 6

6

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
于 2010-07-29T04:36:01.147 に答える
4

おそらく私は何かが欠けているかもしれませんが、あなたが気にかけているのが簡潔であるなら...理由はありません:

@hash && @hash[:key1] && @hash[:key1][:key2]

または、数文字を保存したい場合

@hash && (h = @hash[:key1]) && h[:key2]

これのいずれかの部分が失敗した場合、それ以外の場合はまたはnilに関連付けられた値を返します。:key2true

defined?存在しない場合でも true を返す理由は、:key2参照しているオブジェクトが存在するかどうかをチェックするためです。その場合、ハッシュに存在する[]メソッドのエイリアスであるメソッドですが、nil を返す場合の場合、fetch メソッドがなく、が返されます。そうは言っても、埋め込まれたハッシュを深く掘り下げる必要がある場合、ある時点で次のように呼び出す方が効率的になります。fetch@hash[:key1]nilniln

defined?(@hash[:key1][:key2][:key3]) && @hash[:key1][:key2][:key3]
于 2010-07-29T04:52:26.667 に答える
2

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'skey2

また、呼び出す前にhash[key1]'s値にメソッドがあることを確認する場合は、次のようにします。has_key?

!hash.nil? && (hash.has_key?(key1) ? hash[key1].respond_to?(:has_key?) &&
   hash[key1].has_key?(key2) : false)
于 2010-07-28T18:57:02.153 に答える
0
@hash[:key1].has_key? :key2
于 2010-07-28T18:13:44.427 に答える
0

私が発見したもう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を取得します。

于 2012-11-29T02:37:13.213 に答える
0

@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)
于 2010-07-28T23:54:58.800 に答える