danynl
danynl

Reputation: 299

check hash value within an array

I have an array (array1) of hashes that looks like this :

array1 = [
           {:ID=>"1", :value=>"abc"},
           {:ID=>"2", :value=>"def"}
         ]

I can loop over each hash and check each hash value manually:

array1.each do |h|
  if h.has_value?("def")
    #do something
  end
end

Is there a way to check if the hash value "abc" exists within a hash inside the array without having to iterate over the array?

Upvotes: 1

Views: 2346

Answers (4)

Eric Duminil
Eric Duminil

Reputation: 54233

You obviously have to iterate at least once over the elements of your array.

If you do this often, you should use another data format:

array1 = [
  { ID: '1', value: 'abc' },
  { ID: '2', value: 'def' },
  { ID: '3', value: 'abc' }
]

lookup_table = array1.each_with_object(Hash.new { |h, k| h[k] = [] }) do |hash, table|
  table[hash[:value]] << hash[:ID]
end

p lookup_table
# {"abc"=>["1", "3"], "def"=>["2"]}
p lookup_table['abc']
# ["1", "3"]

As a bonus, it gives you all the IDs for which this value is found, and it gives it fast.

If you just want to know if there's a value somewhere in your hashes, you could use a Set:

require 'set'
all_values = Set.new(array1.map{|h| h[:value]})
p all_values.include? 'abc'
# true
p all_values.include? 'xyz'
# false

Again, the lookup will be much faster than with an array of hashes.

Upvotes: 0

Cary Swoveland
Cary Swoveland

Reputation: 110685

One way or another, you can't avoid iterating over the array. Here's one way.

array1.flat_map(&:values).include?("def")
  #=> true

Note

array1.flat_map(&:values)
  #=> ["1", "abc", "2", "def"]

Upvotes: 1

aqfaridi
aqfaridi

Reputation: 739

use any? instead of each, it breaks in early stage if found, best case O(1) and worst case O(n)

word = "def"
is_present = array1.any? { |h| h.has_value?(word) }

is_present is true if word is found in hash otherwise false

Upvotes: 2

Ursus
Ursus

Reputation: 30056

find method is the most concise way with an array.

array1.find { |item| item[:value] == 'abc' }

Anyway, if you can start directly with an hash is better but if you have to switch to an hash from an array to have the O(1) lookup, it will probably be slower anyway.

Upvotes: 2

Related Questions