Karsten S.
Karsten S.

Reputation: 2391

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, i.e. smarter way of doing it?

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

Upvotes: 1

Views: 986

Answers (4)

user10805134
user10805134

Reputation: 1

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

Upvotes: 0

trushkevich
trushkevich

Reputation: 2677

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?}

p.s. it would be possible to keep all values including nils 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}

Upvotes: 1

Arup Rakshit
Arup Rakshit

Reputation: 118299

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}

Upvotes: 1

Ju Liu
Ju Liu

Reputation: 3999

Maybe the extract! method in active_support could work?

Upvotes: 1

Related Questions