Хэш удалить все, кроме определенных ключей

85

Я хотел бы удалить все ключи из хеша, кроме данного ключа.

Например:

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

Я хочу удалить все, кроме "firstName" и / или "address"

благодаря

Glarkou
источник

Ответы:

50

Некоторые другие варианты:

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

Или вы можете сделать это:

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

Итак, теперь вы можете просто сказать:

h.select_keys("age", "address")
Джейк Демпси
источник
1
Мне нравится использовать массив, чтобы можно было очень быстро добавлять новые ключи вместо дополнительных операторов OR. Расширение Hash тоже классное :)
Джейк Демпси
1
Благодарю. Гораздо более исчерпывающий ответ!
glarkou 08
Это только для рельсов? или рубин вообще?
Фади
280

О чем slice?

hash.slice('firstName', 'lastName')
 # => { 'firstName' => 'John', 'lastName' => 'Smith' }
Марио Угер
источник
9
В вопросе конкретно не упоминается Rails, но он помечен как таковой. Это лучший вариант при использовании Rails или core_ext.
Калеб Харт,
3
Да, это причина, по которой я предложил slice.
Марио Уэр
этот ответ должен быть первым!
mmike
@DimaMelnik Хеши по своей сути не имеют порядка.
Джошуа Пинтер
2
Hash # slice теперь является чистым Ruby, Rails не нужен.
аким
6

Hash # select делает то, что вы хотите:

   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}

Изменить (для комментария):

предполагая, что h - ваш хэш выше:

h.select {|k,v| k == "age" || k == "address" }
Джим Девиль
источник
Что, если я хочу выбрать в своем примере «возраст» и «адрес»?
glarkou 08
2

Если вы используете Rails, обратите внимание на except()метод 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
источник
20
Except сохраняет все, кроме данного. Обратное тому, о чем идет речь.
Кристофер Узбек
1

Вдохновленный ответом Джейка Демпси, этот должен быть быстрее для больших хешей, поскольку он достигает только явных ключей, а не повторяет весь хеш:

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
Старков
источник
0

Для получения очень краткого кода не требуется Rails:

keys = [ "firstName" , "address" ]
# keys = hash.keys - (hash.keys - keys) # uncomment if needed to preserve hash order
keys.zip(hash.values_at *keys).to_h
рибамар
источник
0
hash = { a: true, b: false, c: nil }
hash.extract!(:c) # => { c: nil }
hash # => { a: true, b: false }
ar31an
источник
Это исключает указанные ключи, а не включает указанные ключи. разница тонкая, но важная
BKSpurgeon