除特定键外,哈希表删除所有内容

97
我想从哈希表中除了给定的键之外,移除所有其他的键。 例如:
{
 "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”之外的所有内容。

7个回答

318
关于Hash#slice呢?
hash.slice('firstName', 'lastName')
 # => { 'firstName' => 'John', 'lastName' => 'Smith' }

自2.5版本开始在Ruby中可用


10
问题并没有特别提到Rails,但标签中有这个词。在使用Rails或core_ext时,这是最好的选择。 - Caleb Hearth
3
是的,这就是我建议使用“切片”的原因。 - Mario Uher
这个答案应该是第一个! - mmike
@DimaMelnik 哈希表本质上没有顺序。 - Joshua Pinter
9
现在Hash#slice是纯Ruby实现的,不再需要Rails。 - akim
这应该是正确的答案。简洁明了,没有垃圾代码。 - Matheus Porto

54

其他一些选项:

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扩展也很酷 :) - Jake Dempsey
1
谢谢。非常全面的回答! - glarkou
这只针对Rails吗?还是适用于Ruby的所有情况? - Fadi
新访客,请查看下面得分为200的“slice”答案。这是首选答案。 - alex

8
如果你正在使用Rails,请考虑ActiveSupport的except()方法: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 }

24
Except 保留除给定内容之外的所有内容,与问题所涉及的相反。 - Christopher Oezbek

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

5
hash = { a: true, b: false, c: nil }
hash.extract!(:c) # => { c: nil }
hash # => { a: true, b: false }

这个排除指定的键,而不是包含指定的键。这个差别微妙但很重要。 - BenKoshy

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
受到杰克·登普西的回答的启发,这个方法对于大型哈希表来说应该更快,因为它只查找显式的键,而不是遍历整个哈希表。
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

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接