문제

Is there a non-destructive way of deleting a key value pair from a hash?

For example, if you did

original_hash = {:foo => :bar}
new_hash = original_hash
new_hash = new_hash.reject{|key, _| key == :foo}

or

original_hash = {:foo => :bar}
new_hash = original_hash
new_hash = new_hash.dup
new_hash.delete(:foo)

then original_hash is unchanged, and new_hash is changed, but they're a tad verbose. However, if you did

original_hash = {:foo => :bar}
new_hash = original_hash
new_hash.delete(:foo)

then original_hash is changed, which isn't what I want.

Is there a single method that does what I want?

도움이 되었습니까?

해결책 2

ActiveSupport provides a hash extension: Hash#except. It allows you to return a new hash except specified keys without modifying the original.

Assuming you have installed the active_support gem:

ruby-1.9.3> require 'active_support/core_ext/hash/except.rb'
 => true
 ruby-1.9.3> a = {x: 2, y: 1, z: 3}
 => {:x=>2, :y=>1, :z=>3} 
ruby-1.9.3> b = a.except(:x)
 => {:y=>1, :z=>3} 
ruby-1.9.3> c = a.except(:x, :y)
 => {:z=>3} 
ruby-1.9.3> a
 => {:x=>2, :y=>1, :z=>3} 
ruby-1.9.3> b
 => {:y=>1, :z=>3} 
ruby-1.9.3> c
 => {:z=>3} 

다른 팁

Yes, you want reject:

new_hash = original_hash.reject{|key, _| key == :foo}

The problem is that new_hash is a reference unless you explicitly tell Ruby to duplicate the object. You're on the right track using dup, the only thing I might recommend is to do

new_hash = original_hash.dup 

because I think thats more explicit about what you're doing.

What about chaining the dup to make it less verbose?

new_hash = original_hash.dup.delete_if{|key, _| key == :foo}
original_hash.clone.tap {|h| h.delete key}

tap is arguably less clunky than declaring a new variable, mostly because it's on the same line.

clone is, I think, more explicitly a flat copy than dup, though of course for hashes it makes little difference.

라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top