tags:

views:

83

answers:

3

I'm trying to get a common element from a group of arrays in Ruby. Normally, you can use the & operator to compare two arrays, which returns elements that are present or common in both arrays. This is all good, except when you're trying to get common elements from more than two arrays. However, I want to get common elements from an unknown, dynamic number of arrays, which are stored in a hash.

I had to resort to using the eval() method in ruby, which executes a string as actual code. Here's the function I wrote:

  def get_common_elements_for_hash_of_arrays(hash) # get an array of common elements contained in a hash of arrays, for every array in the hash.
       # ["1","2","3"] & ["2","4","5"] & ["2","5","6"] # => ["2"]
       # eval("[\"1\",\"2\",\"3\"] & [\"2\",\"4\",\"5\"] & [\"2\",\"5\",\"6\"]") # => ["2"]
       eval_string_array = Array.new # an array to store strings of Arrays, ie: "[\"2\",\"5\",\"6\"]", which we will join with & to get all common elements
       hash.each do |key, array|
          eval_string_array << array.inspect 
       end
       eval_string = eval_string_array.join(" & ") # create eval string delimited with a & so we can get common values 
       return eval(eval_string)
  end

example_hash = {:item_0 => ["1","2","3"], :item_1 => ["2","4","5"], :item_2 => ["2","5","6"] }
puts  get_common_elements_for_hash_of_arrays(example_hash) # => 2

This works and is great, but I'm wondering...eval, really? Is this the best way to do it? Are there even any other ways to accomplish this(besides a recursive function, of course). If anyone has any suggestions, I'm all ears.

Otherwise, Feel free to use this code if you need to grab a common item or element from a group or hash of arrays, this code can also easily be adapted to search an array of arrays.

A: 

Can't you just do a comparison of the first two, take the result and compare it to the next one etc? That seems to meet your criteria.

Beanish
+8  A: 

Behold the power of inject! ;)

[[1,2,3],[1,3,5],[1,5,6]].inject(&:&)
=> [1]

As Jordan mentioned, if your version of Ruby lacks support for &-notation, just use

inject{|acc,elem| acc & elem}
Mladen Jablanović
Clever! So just applying this to hash.values should do the trick.
miorel
Jordan
@Jordan: Thanks, I updated the answer. I deliberately omitted the `hash.values` part because IMHO it just obscures the point.
Mladen Jablanović
Awesome. That'll do it. Thanks guys- Take that, eval!
Hulihan Applications
Marc-André Lafortune
Michael Kohl
Mladen Jablanović
A: 

Why not do this:

def get_common_elements_for_hash_of_arrays(hash)
    ret = nil
    hash.each do |key, array|
        if ret.nil? then
            ret = array
        else
            ret = array & ret
        end
    end
    ret = Array.new if ret.nil? # give back empty array if passed empty hash
    return ret
end
miorel