比较二维数组

时间:2015-03-25 06:19:55

标签: ruby 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"]]

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"]]

我想计算两个数组中的类似行,而不考虑字符大小写,即"h25.12"等于"H25.12"

我试过了,

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

但是(a - b)会返回

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

我需要将计数设为5,因为当我们不考虑字符大小写时,有五个相似的行。

8 个答案:

答案 0 :(得分:3)

而不是a - b你应该这样做:

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

答案 1 :(得分:2)

您可以将数组转换为哈希,并将Enumerable#count与块一起使用。

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

答案 2 :(得分:1)

它会将内部数组的第二个元素转换为两个数组的大写,然后你可以执行减法,然后它将返回你想要的精确结果

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

答案 3 :(得分:1)

您可以压缩它们,然后使用计数块形式:

a.zip(b).count{|e| e[0][1].downcase == e[1][1].downcase}

答案 4 :(得分:0)

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

以上将ab映射到第二个子数组元素为小写的新数组。

答案 5 :(得分:0)

你想要计算相似,所以&(AND)操作更合适。

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

答案 6 :(得分:0)

使用Proc和“&”:

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

为了更好地理解,让我们简化它:

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

答案 7 :(得分:0)

我假设a的第i个元素要与b的第i个元素进行比较。 (编辑:OP的后续评论确认了这种解释。)

我倾向于使用索引来避免构建相对较大的临时数组。以下是两种可能的方法。

#1使用指数

[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使用Refinements

我提供此解决方案的目的是说明Refinements的用法。我不会争论它是否适用于手头的问题,但这个问题为展示如何应用该技术提供了良好的工具。

我无法弄清楚如何最好地做到这一点,所以我在SO上发布了这个question。我已经在下面申请了@ ZackAnderson的答案。

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

我可以使用Enumerable#zip,但对于多样性,我会将Object#to_enumKernel#loopEnumerator#next结合使用:

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