Hash usuwa wszystko oprócz określonych kluczy

85

Chciałbym usunąć każdy klucz z skrótu oprócz danego klucza.

Na przykład:

{
 "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"
     }
 ]
}

Chcę usunąć wszystko oprócz „imię” i / lub „adres”

Dzięki

glarkou
źródło

Odpowiedzi:

50

Kilka innych opcji:

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

Lub możesz to zrobić:

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

Możesz więc teraz po prostu powiedzieć:

h.select_keys("age", "address")
Jake Dempsey
źródło
1
Lubię używać tablicy, dzięki czemu bardzo szybko i łatwo można dodawać nowe klucze zamiast większej liczby instrukcji OR. Rozszerzenie Hash też jest fajne :)
Jake Dempsey,
1
Dzięki. O wiele bardziej wyczerpująca odpowiedź!
glarkou
Czy to tylko dla szyn? czy ogólnie rubin?
Fadi
280

O co chodzi slice?

hash.slice('firstName', 'lastName')
 # => { 'firstName' => 'John', 'lastName' => 'Smith' }
Mario Uher
źródło
9
Pytanie nie wspominało konkretnie o Railsach, ale zostało oznaczone jako takie. To najlepsza opcja, gdy używasz Railsów lub core_ext.
Caleb Hearth
3
Tak, to jest powód, dla którego zasugerowałem slice.
Mario Uher,
ta odpowiedź powinna być pierwsza!
mmike,
@DimaMelnik Hashe z natury nie mają kolejności.
Joshua Pinter,
2
Hash # slice jest teraz czystym Rubinem, Railsy nie są potrzebne.
akim
6

Hash # select robi to, co chcesz:

   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}

Edytuj (dla komentarza):

zakładając, że h jest twoim hashem powyżej:

h.select {|k,v| k == "age" || k == "address" }
Jim Deville
źródło
A jeśli chcę wybrać „wiek” i „adres” z mojego przykładu?
glarkou
2

Jeśli używasz Railsów, rozważ except()metodę ActiveSupport : 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
źródło
20
Z wyjątkiem przechowuje wszystko oprócz tego, co podano. Odwrotność tego, o co chodzi w pytaniu.
Christopher Oezbek
1

Zainspirowany odpowiedzią Jake'a Dempseya, ten powinien być szybszy dla dużych haszów, ponieważ tylko wyskakuje jawne klucze, a nie iteruje przez cały hash:

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
źródło
0

Żadne Railsy nie są potrzebne do uzyskania bardzo zwięzłego kodu:

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
źródło
0
hash = { a: true, b: false, c: nil }
hash.extract!(:c) # => { c: nil }
hash # => { a: true, b: false }
ar31an
źródło
Wyklucza to określone klucze, a nie obejmuje określone klucze. różnica jest subtelna, ale ważna
BKSpurgeon,