简体   繁体   中英

select and delete from hash in ruby

In a method I get a list of options passed in. Some are related to a particular scope. I want to store those special keys in another hash to be able to pass it to a different method, and delete them from the original hash.

(I'm actually writing a rails simple_form custom input, but that doesn't matter)

I have the following code:

all_options = { :key1 => 1, :key2 => 2, :something_else => 42 }

my_keys = [:key1, :key2, :key3, :key4]
my_options = all_options.select {|k,v| my_keys.include?(k)}
all_options.delete_if {|k,v| my_keys.include?(k)}

# expecting
my_options == { :key1 => 1, :key2 => 2 }
all_options == { :something_else => 42 }

Now my question is there a better, ie smarter way of doing it?

Maybe it's just sugar, but I want to know.

Maybe the extract! method in active_support could work?

I know only Ruby. So here my Ruby approach :

all_options = { :key1 => 1, :key2 => 2, :something_else => 42 }

my_keys = [:key1, :key2, :key3, :key4]

#below statement is your my_options

Hash[my_keys.map{|i| [i,all_options.delete(i)] if all_options.has_key? i }.compact]
# => {:key1=>1, :key2=>2}

all_options
# => {:something_else=>42}
all_options = { :key1 => 1, :key2 => 2, :something_else => 42 }
my_keys = [:key1, :key2, :key3, :key4]

my_options = my_keys.inject({}) {|h,k| h[k] = all_options.delete(k) if all_options.key?(k);h}

all_options
# => {:something_else=>42}
my_options
# => {:key1=>1, :key2=>2}

here's a way to improve Ju Liu's answer:

all_options = { :key1 => 1, :key2 => 2, :something_else => 42 }
my_keys = [:key1, :key2, :key3, :key4]

my_options = all_options.extract!(*my_keys).keep_if {|k,v| v}

all_options
# => {:something_else=>42}
my_options
# => {:key1=>1, :key2=>2}

however you'll lose your options if any key in a all_options hash has an actual value of nil or false (don't know if you need to keep them):

all_options = { :key1 => 1, :key2 => nil, :something_else => 42 }

here's a way to keep false 's

my_options = all_options.extract!(*my_keys).keep_if {|k,v| !v.nil?}

ps it would be possible to keep all values including nil s if you store the keys from all_options :

all_options = { :key1 => 1, :key2 => 2, :something_else => 42 }
all_keys = all_options.keys
my_keys = [:key1, :key2, :key3, :key4]

my_options = all_options.extract!(*my_keys).keep_if {|k,v| all_keys.include?(k)}

all_options
# => {:something_else=>42}
my_options
# => {:key1=>1, :key2=>2}
all_options = { key1: 1, key2: 2, something_else: 42 }
my_keys = [:key1, :key2, :key3, :key4]

my_options = my_keys.each_with_object({}) do |key, hash|
  hash[key] = all_options.delete(key) if all_options.key?(key)
end

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM