What is a elegant way in Ruby to tell if a variable is a Hash or an Array?
Solution 1
You can just do:
@some_var.class == Hash
or also something like:
@some_var.is_a?(Hash)
It's worth noting that the "is_a?" method is true if the class is anywhere in the objects ancestry tree. for instance:
@some_var.is_a?(Object) # => true
the above is true if @some_var is an instance of a hash or other class that stems from Object. So, if you want a strict match on the class type, using the == or instance_of? method is probably what you're looking for.
Solution 2
First of all, the best answer for the literal question is
Hash === @some_var
But the question really should have been answered by showing how to do duck-typing here. That depends a bit on what kind of duck you need.
@some_var.respond_to?(:each_pair)
or
@some_var.respond_to?(:has_key?)
or even
@some_var.respond_to?(:to_hash)
may be right depending on the application.
Solution 3
Usually in ruby when you are looking for "type" you are actually wanting the "duck-type" or "does is quack like a duck?". You would see if it responds to a certain method:
@some_var.respond_to?(:each)
You can iterate over @some_var because it responds to :each
If you really want to know the type and if it is Hash or Array then you can do:
["Hash", "Array"].include?(@some_var.class) #=> check both through instance class
@some_var.kind_of?(Hash) #=> to check each at once
@some_var.is_a?(Array) #=> same as kind_of
Solution 4
Hash === @some_var #=> return Boolean
this can also be used with case statement
case @some_var
when Hash
...
when Array
...
end
Solution 5
In practice, you will often want to act differently depending on whether a variable is an Array or a Hash, not just mere tell. In this situation, an elegant idiom is the following:
case item
when Array
#do something
when Hash
#do something else
end
Note that you don't call the .class
method on item
.
Related videos on Youtube
drhyde
Updated on December 28, 2020Comments
-
drhyde over 3 years
To check what
@some_var
is, I am doing aif @some_var.class.to_s == 'Hash'
I am sure there is a more elegant way to check if
@some_var
is aHash
or anArray
. -
Fábio Batista over 13 years
is_a?
is the best option, since it also returnstrue
for subclasses. -
juan2raid over 13 yearsThis won't work if your code is dependent on the ordering of the data(e.g. if you are using each_with_index). The order of the elements is implemented differently between hashes and arrays and it is different between ruby versions.(intertwingly.net/slides/2008/oscon/ruby19/22)
-
oligan over 13 years@juan2raid: If order is important, then call
sort
on it first. -
unflores over 10 yearsBe careful, this could really screw you if someone ends up passing you an instance of ActiveSupport::HashWithIndifferentAccess. Which responds like a hash, but is not in fact a Hash. :(
-
OBCENEIKON about 9 years@Brandon second example should convert the class to string.<br/>
["Hash", "Array"].include?(@some_var.class.to_s) #=> check both through instance class
-
Stilzk1n almost 8 years@unflores
ActiveSupport::HashWithIndifferentAccess
inherits from Hash, hence@some_var.is_a?(Hash)
will return true in this case as well. (I just had the same question and HashWithIndifferentAccess case and got a bit confused from your comment...so I wanted to clarify) -
Tom Lord almost 8 yearsNote that this does not work for subclasses! For example, if you have an
ActiveRecord::Collection
and tryinstance_of?(Array)
then this will returnfalse
, whereasis_a?(Array)
will returntrue
. -
FilBot3 almost 7 yearsI've also had issues with using this method in
case
statments. Seemed to only work for me inif..else
statements. -
mtrussell about 3 yearsRubocop seems to prefer
instance_of?(Hash)