1

I have a hash, which contains a hash, which contains a number of arrays, like this:

{ "bob" =>
    {  
       "foo" => [1, 3, 5],
       "bar" => [2, 4, 6]
    },
  "fred" =>
    {  
       "foo" => [1, 7, 9],
       "bar" => [8, 10, 12]
    }
} 

I would like to compare the arrays against the other arrays, and then alert me if they are duplicates. It is possible for hash["bob"]["foo"] and hash["fred"]["foo"] to have duplicates, but not for hash["bob"]["foo"] and hash["bob"]["bar"]. Same with hash["fred"].

I can't even figure out where to begin with this one. I suspect inject will be involved somewhere, but I could be wrong.

1
  • Eugene - please clarify, are you looking to see if the entire array is a duplicate or just elements within the arrays? Commented Oct 17, 2012 at 2:48

4 Answers 4

1

This snippet will return an array of duplicates for each key. Duplicates can only be generated for equal keys.

duplicates = (keys = h.values.map(&:keys).flatten.uniq).map do |key|
  {key =>  h.values.map { |h| h[key] }.inject(&:&)}
end

This will return [{"foo"=>[1]}, {"bar"=>[]}] which indicates that the key foo was the only one containing a duplicate of 1.

The snippet above assume h is the variable name of your hash.

Sign up to request clarification or add additional context in comments.

Comments

1
h =  {
  "bob" =>
    {
       "foo" => [1, 3, 5],
       "bar" => [2, 4, 6]
    },
  "fred" =>
    {  
       "foo" => [1, 7, 9],
       "bar" => [1, 10, 12]
    }
}

h.each do |k, v|
  numbers = v.values.flatten
  puts k if numbers.length > numbers.uniq.length
end

2 Comments

Why aren't you using the Hashes each() method instead of manually fetching the value to every key?
Because I didn't know what was it's behavior. Now I do
0

There are many ways to do it. Here's one that should be easy to read. It works in Ruby 1.9. It uses + to combine two arrays and then uses the uniq! operator to figure out whether there is a duplicate number.

h = { "bob" =>
{  
   "foo" => [1, 3, 5],
   "bar" => [2, 4, 6]
},
"fred" =>
{  
   "foo" => [1, 7, 12],
   "bar" => [8, 10, 12]
}
}

h.each  do |person|
    if (person[1]["foo"] + person[1]["bar"]).uniq! != nil  
        puts "Duplicate in #{person[1]}"
    end
end

Comments

0

I'm not sure what exactly you are looking for. But at look at a possible solution, perhaps you can reuse something.

outer_hash.each do |person, inner_hash|
  seen_arrays = Hash.new

  inner_hash.each do |inner_key, array|
    other = seen_arrays[array]
    if other
      raise "array #{person}/#{inner_key} is a duplicate of #{other}"
    end
    seen_arrays[array] = "#{person}/#{inner_key}"
  end
end

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.