Reputation: 299
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
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 ID
s 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
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
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
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