Delete array of keys in Ruby Hash

19,276

Solution 1

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.

Solution 2

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

Solution 3

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 }

Solution 4

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,..)
Share:
19,276
Artem Kalinchuk
Author by

Artem Kalinchuk

Updated on June 17, 2022

Comments

  • Artem Kalinchuk
    Artem Kalinchuk about 2 years

    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.

  • Artem Kalinchuk
    Artem Kalinchuk over 12 years
    I'm trying to stay away from loops because they're slow and this code is time sensitive.
  • KL-7
    KL-7 over 12 years
    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?
  • Artem Kalinchuk
    Artem Kalinchuk over 12 years
    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.
  • KL-7
    KL-7 over 12 years
    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.
  • undur_gongor
    undur_gongor over 12 years
    +1. I was just going to add this. Of course, it iterates through the items too (even several times).
  • KL-7
    KL-7 over 12 years
    If size of the hash is way bigger than size of the array this approach is less efficient than iterating over an array.
  • Aliaksei Kliuchnikau
    Aliaksei Kliuchnikau over 12 years
    @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 :)
  • steenslag
    steenslag over 12 years
    @Artem Kalinchuk A hash does not loop to find a key, it is way faster than that. Here's how hash is implemented in Ruby:.
  • Artem Kalinchuk
    Artem Kalinchuk over 12 years
    @steenslag what's your solution? delete_if loops. [key1, key2, key3].each {|k| some_hash.delete k } loops too.
  • steenslag
    steenslag over 12 years
    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).
  • steenslag
    steenslag over 12 years
    In other words, i think this is a fine solution.
  • Artem Kalinchuk
    Artem Kalinchuk over 12 years
    Gotcha. I ended up using this solution, it works as expected and executes pretty fast.
  • kuboon
    kuboon about 11 years
    keys.map instead of keys.each returns deleted values array. useful.
  • sokkyoku
    sokkyoku almost 8 years
    This is part of rails, not ruby.