Home > Software design >  Ruby compare hash values by the same keys
Ruby compare hash values by the same keys

Time:09-22

Let's say i have 3 hashes

hash1 = {'a' => 1, 'b' => 2}
hash2 = {'a' => 1, 'b' => 2, 'd' => 3}
hash3 = {'a' => 1, 'b' => 2, 'c' => 4, 'd' => 3}
hash4 = {'c' => 4, 'd' => 3, 'e' = 5}

Expected result

hash1 == hash2 # => true
hash1 == hash3 # => true
hash1 == hash4 # => false (has no common keys to compare their values)
hash2 == hash3 # => true

So basically i want to compare values of the same keys in both hashes while comparing. And give false if there are no common keys

Edit: Tips to @CarySwoveland, his solution works perfectly:

common_keys = hash1.keys & hash2.keys;

    if common_keys.any?
      hash1.values_at(*common_keys) == hash2.values_at(*common_keys);
    else
      false
    end

CodePudding user response:

You could use Set, if I get the answer properly, and check if the first hash is included in the second:

require 'set'

def is_included?(hash_a, hash_b)
  return hash_a.size == (hash_a.to_set & hash_b.to_set).size
end

So, you can check this way:

hash1 = {'a' => 1, 'b' => 2}
hash2 = {'a' => 1, 'b' => 2, 'd' => 3}
hash3 = {'a' => 1, 'b' => 2, 'c' => 4, 'd' => 3}
hash4 = {'c' => 4, 'd' => 3, 'e' => 5}

is_included?(hash1, hash2) #=> true
is_included?(hash1, hash3) #=> true
is_included?(hash1, hash4) #=> false
is_included?(hash2, hash3) #=> true

Also just return hash_a.to_set <= hash_b.to_set should work.

CodePudding user response:

Edit: this solution is not working for some cases not mentioned in the original question, so this answer should fit better: https://stackoverflow.com/a/69280216/299774

This formula will give you what you want (for the provided examples)

def compare(first, second)
  ((first.to_a & second.to_a) <=> first.to_a) >= 0
end

How does it work?

It transforms hashes into array of key-value pairs (also arrays)

> hash1.to_a
=> [["a", 1], ["b", 2]]

So now you can do neat things, treat arrays as sets and find their intersections (the common elements):

> hash1.to_a & hash2.to_a
=> [["a", 1], ["b", 2]]
> hash1.to_a & hash4.to_a
=> []

What is left, is to check if the intersection is included in one of those arrays, the rocket method <=> is very useful, will give you 0 when arrays are identical, 1 if the right one is included in the left one, and -1 otherwise. You seem to be interested in the first two cases, hence >= 0

  • Related