3 Stimmen

Verschachtelter Hash definiert?()

Wie lässt sich am einfachsten feststellen, ob @hash[:key1][:key2] definiert ist, die keinen Fehler auslöst, wenn @hash o @hash[:key1] gleich null sind?

defined?(@hash[:key1][:key2]) gibt True zurück, wenn @hash[:key1] existiert (sie bestimmt nicht, ob :key2 definiert ist)

6voto

Konstantin Haase Punkte 25071

Wenn Sie ActiveSupport (Rails) oder Backports verwenden, können Sie try :

@hash[:key1].try(:fetch, :key2)

Sie könnten sogar mit @hash unter nil :

@hash.try(:fetch, :key1).try(:fetch, :key2)

Wenn Sie wollen @hash um bei einem fehlenden Schlüssel immer einen Hash zurückzugeben:

@hash = Hash.new { |h,k| h[k] = {} }
@hash[:foo] # => {}

Sie könnten dies auch rekursiv definieren:

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}}}

Aber um Ihre Frage zu beantworten:

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

4voto

Geoff Lanotte Punkte 7460

Vielleicht übersehe ich etwas, aber wenn es Ihnen nur um Prägnanz geht... warum nicht:

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

oder wenn Sie ein paar Zeichen sparen wollen

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

Wenn ein Teil dieses Vorgangs fehlschlägt, gibt er nil andernfalls gibt es den Wert zurück, der mit :key2 o true .

Der Grund für die defined? gibt true zurück, auch wenn :key2 nicht vorhanden ist, weil es nur prüft, ob das Objekt, auf das Sie verweisen, existiert, was in diesem Fall die Methode [] die ein Alias für die Methode fetch die im Hash vorhanden ist @hash[:key1] aber wenn das nichts ergibt, gibt es keine Fetch-Methode auf nil und es würde zurückkommen nil . Dennoch, wenn Sie gehen müssten n tief in einen eingebetteten Hash, irgendwann wäre es effizienter, ihn aufzurufen:

defined?(@hash[:key1][:key2][:key3]) && @hash[:key1][:key2][:key3]

0 Stimmen

x = {a:{b:{c:3}}} defined?(x[:z]) # => "method"

0 Stimmen

@hash = {:key1 => true} @hash && @hash[:key1] && @hash[:key1][:key2] # => NoMethodError (undefined method []' for true:TrueClass)`

2voto

mikej Punkte 63496

Hash#fetch verwenden

Sie können die Hash#fetch Methode mit einem Standardwert von {} so dass es sicher ist, die has_key? auch wenn der Schlüssel der ersten Ebene nicht existiert. z.B.

!hash.nil? && hash.fetch(key1, {}).has_key?(key2)

Alternative

Alternativ können Sie auch den Bedingungsoperator verwenden, z. B.

!hash.nil? && (hash.has_key?(key1) ? hash[key1].has_key?(key2) : false)

d.h. wenn hash hat keinen Schlüssel key1 dann einfach zurückgeben false ohne nach dem Schlüssel der zweiten Ebene zu suchen. Wenn es eine key1 dann das Ergebnis der Prüfung zurückgeben key1's Wert für key2 .

Wenn Sie außerdem überprüfen möchten, ob hash[key1]'s Wert hat einen has_key? Methode, bevor Sie sie aufrufen:

!hash.nil? && (hash.has_key?(key1) ? hash[key1].respond_to?(:has_key?) &&
   hash[key1].has_key?(key2) : false)

0voto

Adrian Punkte 14376
@hash[:key1].has_key? :key2

0 Stimmen

Dies wird die NoMethodError: undefined method has_key?' für nil:NilClass` if @hash hat keinen Wert für :key1

0 Stimmen

@Wayne jep, fetch ist einer der Ansätze, die ich in meiner Antwort vorgeschlagen habe. Siehe unten (oder oben, je nach SOs Zufallsgenerator!)

1 Stimmen

@mikej, Sie haben Recht. Entschuldigung für meine Redundanz. Ich habe meinen Kommentar gelöscht, da er nicht sehr nützlich war.

0voto

taw Punkte 17354

Wenn Sie sich nicht um die Unterscheidung von nicht existierenden @hash[:key1][:key2] (auf einer der 3 Ebenen) von @hash[:key1][:key2] == nil Das ist ziemlich sauber und funktioniert für jede Tiefe:

[:key1,:key2].inject(hash){|h,k| h && h[k]}

Wenn Sie wollen nil als vorhanden behandelt werden soll, verwenden Sie stattdessen dies:

(hash[:key1].has_key?(:key2) rescue false)

0 Stimmen

Der Missbrauch von Ausnahmen für den normalen Programmablauf ist afaik ein Codegeruch.

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X