19

How would I go about deleting an array of keys in a hash? For example, you can call:

hash.delete(some_key)

But how can I do this:

hash.delete([key1,key2,key3,...])

without needing to looping manually.

1
  • If you have an array then you'll iterate through it in any case. Maybe you don't need to store these keys in array, but delete them immediately. Commented Feb 1, 2012 at 14:33

5 Answers 5

27

You can iterate over an array of keys and delete everyone of them:

[key1, key2, key3].each { |k| some_hash.delete k }

Can't remember any better solution.

Sign up to request clarification or add additional context in comments.

9 Comments

I'm trying to stay away from loops because they're slow and this code is time sensitive.
I see, but if you deal with an array of keys you have to iterate over it anyway. What are the sizes of hash and array in your case?
I don't really need to iterate through the array of keys, just need to delete those keys in the hash. The hash has about 20,000 items but it has to loop multiple times with items being different each time.
I meant that any method that you would use to delete values from the hash by keys from the array will need to iterate over that array (it'll at least look through each key). That means computational time is at least linear of the length of the array (multiplied by complexity of deleting by key from hash). Though, I might be wrong and would be happy to see a better solution.
You loop the array once; you search the hash (which is fast) multiple times. I tried it; created a hash with 20_000 random 5 letter words and an array with 10_000 5 letter words. The line by @KL-7 took 0.02 seconds to execute (and this computer is old).
|
17

This is exactly what you are looking for... You can do it like this without looping through the array unnecessarily.

keys_to_delete = [key1, key2, key3]
hash_array.except!(*keys_to_delete)

The result is stored in hash_array

1 Comment

This is part of rails, not ruby.
11

You can try to use Hash#delete_if:

delete_if deletes every key-value pair from hsh for which block evaluates to true.

array_hash.delete_if { |key, _| [key1, key2, key3].include? key }

UPDATE If you don't want to iterate over array of keys, you can use Set instead of Array (since Set uses Hash as storage include? is O(1)):

require 'set'
keys = [key1,key2,key3].to_set
array_hash.delete_if { |key, _| keys.include? key }

3 Comments

+1. I was just going to add this. Of course, it iterates through the items too (even several times).
If size of the hash is way bigger than size of the array this approach is less efficient than iterating over an array.
@KL-7, agree, it is always required to do penformance benchmarks before optimizing some code, optimization without measurement may increase execution time and memory consumption. I would not bother to optimize code like this. OP just has several alternatives :)
2

Maybe it's worth to make a method

class Hash
  def delete_by_keys *keys
    keys.each{|k| delete(k)}
  end
end

hash_array.delete_by_keys(key1,key2,..)

1 Comment

keys.map instead of keys.each returns deleted values array. useful.
0

ActiveSupport (part of Rails) implements exactly this, as Hash#except and Hash#except!

def except!(*keys)
    keys.each { |key| delete(key) }
    self
end

See http://apidock.com/rails/v4.0.2/Hash/except%21

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.