简体   繁体   中英

Compare two array of hashes with same keys

I have 2 arrays of hashes with same keys but different values.

A = [{:a=>1, :b=>4, :c=>2},{:a=>2, :b=>1, :c=>3}]
B = [{:a=>1, :b=>1, :c=>2},{:a=>1, :b=>3, :c=>3}]

I'm trying to compare 1st hash in A with 1st hash in B and so on using their keys and identify which key and which value is not matching if they do not match. please help.

    A.each_key do |key|
      if A[key] ==  B[key]
        puts "#{key} match"
      else
        puts "#{key} dont match"

I am not certain which comparisons you want to make, so I will show ways of answering different questions. You want to make pairwise comparisons of two arrays of hashes, but that's really no more difficult than just comparing two hashes, as I will show later. For now, suppose you merely want to compare two hashes:

h1 = {:a=>1, :b=>4, :c=>2, :d=>3 }
h2 = {:a=>1, :b=>1, :c=>2, :e=>5 }

What keys are in h1 or h2 (or both)?

h1.keys | h2.keys
  #=> [:a, :b, :c, :d, :e]

See Array#| .

What keys are in both hashes?

h1.keys & h2.keys
  #=> [:a, :b, :c] 

See Array#& .

What keys are in h1 but not h2 ?

h1.keys - h2.keys
  #=> [:d] 

See Array#- .

What keys are in h2 but not h1 ?

h2.keys - h1.keys #=> [:e] 

What keys are in one hash only?

(h1.keys - h2.keys) | (h2.keys - h1.keys)
  #=> [:d, :e]

or

(h1.keys | h2.keys) - (h1.keys & h2.keys)

What keys are in both hashes and have the same values in both hashes?

(h1.keys & h2.keys).select { |k| h1[k] == h2[k] }
  #=> [:a, :c] 

See Array#select .

What keys are in both hashes and have different values in the two hashes?

(h1.keys & h2.keys).reject { |k| h1[k] == h2[k] }
  #=> [:b] 

Suppose now we had two arrays of hashes:

a1 = [{:a=>1, :b=>4, :c=>2, :d=>3 }, {:a=>2, :b=>1, :c=>3, :d=>4}]
a2 = [{:a=>1, :b=>1, :c=>2, :e=>5 }, {:a=>1, :b=>3, :c=>3, :e=> 6}]

and wished to compare the hashes pairwise. To do that first take the computation of interest above and wrap it in a method. For example:

def keys_in_both_with_different_values(h1, h2)
  (h1.keys & h2.keys).reject { |k| h1[k] == h2[k] }
end

Then write:

a1.zip(a2).map { |h1,h2| keys_in_both_with_different_values(h1, h2) }
  #=> [[:b], [:a, :b]]

See Enumerable#zip .

Since you're comparing elements of arrays...

A.each_with_index do |hasha, index|
  hashb = B[index]
  hasha.each_key do |key|
    if hasha[key] == hashb[key]
      puts "in array #{index} the key #{key} matches"
    else
      puts "in array #{index} the key #{key} doesn't match"
    end
  end
end

edit - added a missing end !

When you are dealing with an array, you should reference an element with open-close bracket '[]' as in

A[index at which lies the element you are looking for]

If you want to access an element in a hash, you want to use open-close bracket with the corresponding key in it, as in

A[:a] 

(referencing the value that corresponds to the key ':a', which is of a type symbol.)

In this case, the arrays in question are such that hashes are nested within an array. So for example, the expression B[0][:c] will give 2.

To compare the 1st hash in A with the 1st hash in B, the 2nd hash in A with the second hash in B and so forth, you can use each_with_index method on an Array object ,like so;

A = [{:a=>1, :b=>4, :c=>2},{:a=>2, :b=>1, :c=>3}]
B = [{:a=>1, :b=>1, :c=>2},{:a=>1, :b=>3, :c=>3}]
sym = [:a, :b, :c]

A.each_with_index do |hash_a, idx_a|
  sym.each do |sym|
    if A[idx_a][sym] == B[idx_a][sym]
      puts "Match found! (key -- :#{sym}, value -- #{A[idx_a][sym]})"
    else
      puts "No match here."
    end 
  end
end

which is checking the values based on the keys, which are symbols, in the following order; :a -> :b -> :c -> :a -> :b -> :c This will print out;

Match found! (key -- :a, value -- 1)
No match here.
Match found! (key -- :c, value -- 2)
No match here.
No match here.
Match found! (key -- :c, value -- 3)

The method each_with_index may look a little bit cryptic if you are not familiar with it. If you are uncomfortable with it you might want to check;
http://apidock.com/ruby/Enumerable/each_with_index

Last but not least, don't forget to add 'end'(s) at the end of a block (ie the code between do/end) and if statement in your code.

I hope it helps.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM