Hash entfernt alle außer bestimmten Schlüsseln

83

Ich möchte jeden Schlüssel mit Ausnahme eines bestimmten Schlüssels aus einem Hash entfernen.

Zum Beispiel:

{
 "firstName": "John",
 "lastName": "Smith",
 "age": 25,
 "address":
 {
     "streetAddress": "21 2nd Street",
     "city": "New York",
     "state": "NY",
     "postalCode": "10021"
 },
 "phoneNumber":
 [
     {
       "type": "home",
       "number": "212 555-1234"
     },
     {
       "type": "fax",
       "number": "646 555-4567"
     }
 ]
}

Ich möchte alles außer "Vorname" und / oder "Adresse" entfernen.

Vielen Dank

Glarkou
quelle

Antworten:

50

Einige andere Optionen:

h.select {|k,v| ["age", "address"].include?(k) }

Oder Sie könnten dies tun:

class Hash
  def select_keys(*args)
    select {|k,v| args.include?(k) }
  end
end

Sie können jetzt einfach sagen:

h.select_keys("age", "address")
Jake Dempsey
quelle
1
Ich mag es, das Array zu verwenden, damit es sehr schnell und einfach neue Schlüssel anstelle von mehr OR-Anweisungen hinzufügen kann. Die Hash-Erweiterung ist auch ein bisschen cool :)
Jake Dempsey
1
Vielen Dank. Viel umfassendere Antwort!
Glarkou
Gilt das nur für Schienen? oder Rubin im Allgemeinen?
Fadi
276

Was ist mit slice?

hash.slice('firstName', 'lastName')
 # => { 'firstName' => 'John', 'lastName' => 'Smith' }
Mario Uher
quelle
9
In der Frage wurde Rails nicht ausdrücklich erwähnt, sie ist jedoch als solche gekennzeichnet. Dies ist die beste Option bei Verwendung von Rails oder core_ext.
Caleb Hearth
3
Ja, das ist der Grund, den ich vorgeschlagen habe slice.
Mario Uher
Diese Antwort sollte die erste sein!
mmike
@DimaMelnik Hashes haben von Natur aus keine Bestellung.
Joshua Pinter
2
Hash # Slice ist jetzt reines Ruby, Rails wird nicht benötigt.
Akim
6

Hash # select macht was Sie wollen:

   h = { "a" => 100, "b" => 200, "c" => 300 }
   h.select {|k,v| k > "a"}  #=> {"b" => 200, "c" => 300}
   h.select {|k,v| v < 200}  #=> {"a" => 100}

Bearbeiten (für Kommentar):

Angenommen, h ist Ihr Hash oben:

h.select {|k,v| k == "age" || k == "address" }
Jim Deville
quelle
Was ist, wenn ich in meinem Beispiel "Alter" und "Adresse" auswählen möchte?
Glarkou
2

Wenn Sie Rails verwenden, ziehen Sie bitte die ActiveSupport- except()Methode in Betracht : http://apidock.com/rails/Hash/except

hash = { a: true, b: false, c: nil}
hash.except!(:c) # => { a: true, b: false}
hash # => { a: true, b: false }
Asiniy
quelle
19
Außer hält alles außer dem Gegebenen. Das Gegenteil von dem, worum es in der Frage geht.
Christopher Oezbek
1

Inspiriert von Jake Dempseys Antwort sollte diese für große Hashes schneller sein, da nur explizite Schlüssel angezeigt werden, anstatt den gesamten Hash zu durchlaufen:

class Hash
  def select_keys(*args)
    filtered_hash = {}
    args.each do |arg|
      filtered_hash[arg] = self[arg] if self.has_key?(arg)
    end
    return filtered_hash
  end
end
starkovv
quelle
0

Es sind keine Schienen erforderlich, um einen sehr präzisen Code zu erhalten:

keys = [ "firstName" , "address" ]
# keys = hash.keys - (hash.keys - keys) # uncomment if needed to preserve hash order
keys.zip(hash.values_at *keys).to_h
Ribamar
quelle
0
hash = { a: true, b: false, c: nil }
hash.extract!(:c) # => { c: nil }
hash # => { a: true, b: false }
ar31an
quelle
Dies schließt die angegebenen Schlüssel aus und nicht die angegebenen Schlüssel. Der Unterschied ist subtil, aber wichtig
BKSpurgeon