Compare two-dimensional arrays

I have two two-dimensional arrays,

a = [[17360, "Z51.89"], [17361, "S93.601A"], [17362, "H66.91"], [17363, "H25.12"], [17364, "Z01.01"], [17365, "Z00.121"], [17366, "Z00.129"], [17367, "K57.90"], [17368, "I63.9"]] 

and

 b = [[17360, "I87.2"], [17361, "s93.601"], [17362, "h66.91"], [17363, "h25.12"], [17364, "Z51.89"], [17365, "z00.121"], [17366, "z00.129"], [17367, "k55.9"], [17368, "I63.9"]] 

I would like to read similar strings in both arrays regardless of the character case, i.e. "h25.12" would be equal to "h25.12" .

I tried,

 count = a.count - (a - b).count 

But (a - b) returns

 [[17360, "Z51.89"], [17361, "S93.601A"], [17362, "H66.91"], [17363, "H25.12"], [17364, "Z01.01"], [17365, "Z00.121"], [17366, "Z00.129"], [17367, "K57.90"]] 

I need an account like 5 , since there are five identical lines, if we do not consider the case of a symbol.

0
source share
8 answers

Instead of a - b you should do the following:

 a.map{|k,v| [k,v.downcase]} - b.map{|k,v| [k,v.downcase]} # case-insensitive 
+3
source

You can convert arrays to Hash and use Enumerable # count with a block.

 b_hash = b.to_h a.to_h.count {|k, v| b_hash[k] && b_hash[k].downcase == v.downcase } # => 5 
+2
source

It will convert the second element of the internal array to uppercase for both arrays, then you can do the subtraction, then it will return the exact result you want

 a.map{|first,second| [first,second.upcase]} - b.map{|first,second| [first,second.upcase]} 
+1
source

You can pin them and then use the block form of count:

 a.zip(b).count{|e| e[0][1].downcase == e[1][1].downcase} 
+1
source
 a.count - (a.map{|e| [e[0],e[1].downcase] } - b.map{|e| [e[0],e[1].downcase] }).count 

The above maps a and b refer to new arrays, where the second element of the sub-array is the bottom.

0
source

You want to consider similar, so the & (AND) operation is more suitable.

 (a.map { |k, v| [k, v.upcase] } & b.map { |k, v| [k, v.upcase] }).count 
0
source

Using Proc and & '

 procedure = Proc.new { |i, j| [i, j.upcase] } (a.map(&procedure) & b.map(&procedure)).count #=> 5 

For a better understanding, simplify it:

 new_a = a.map {|i, j| [i, j.upcase]} new_b = b.map {|i, j| [i, j.upcase]} # Set intersection using '&' (new_a & new_b).count #=> 5 
0
source

I suggested that the ith element a should be compared with the ith element b . (Edit: a subsequent OP comment confirmed this interpretation.)

I would be inclined to use indexes to avoid creating relatively large temporary arrays. Here are two ways to do this.

# 1 Use indexes

 [a.size,b.size].min.size.times.count do |i| af,al=a[i] bf,bl=b[i]; af==bf && al.downcase==bl.downcase end #=> 5 

# 2 Use Refinements

My goal in providing this solution is to illustrate the use of Refinements . I would not argue about its use for this problem, but this problem is a good way to demonstrate how this technique can be applied.

I could not figure out how to do this, so I posted this question on SO. I applied @ZackAnderson answer below.

 module M refine String do alias :dbl_eql :== def ==(other) downcase.dbl_eql(other.downcase) end end refine Array do def ==(other) zip(other).all? {|x, y| x == y} end end end 'a' == 'A' #=> false (as expected) [1,'a'] == [1,'A'] #=> false (as expected) using M 'a' == 'A' #=> true [1,'a'] == [1,'A'] #=> true 

I could use Enumerable # zip , but for a change I will use Object # to_enum and the kernel loop in combination with Enumerator # the following :

 ea, eb = a.to_enum, b.to_enum cnt = 0 loop do cnt += 1 if ea.next == eb.next end cnt #=> 5 
0
source

Source: https://habr.com/ru/post/1216245/


All Articles