Ruby:如何找到2个数组之间的差异,订购问题

时间:2016-09-12 02:18:31

标签: arrays ruby array-difference

我正在尝试计算订单重要的两个数组之间的差异。例如:

array_one = ["A", "B", "C"]
array_two = ["B", "C", "A"]

这将产生3个差异,因为:

array_one[0] != array_two[0]
array_one[1] != array_two[1]
array_one[2] != array_two[2]

另一个例子:

array_one = ["Z", "X", "Y"]
array_two = ["Z", "W", "Y"]

这会产生1,因为:

array_one[0] == array_two[0]
array_one[1] != array_two[1]
array_one[2] == array_two[2]

任何建议都非常感谢。

6 个答案:

答案 0 :(得分:5)

这个怎么样

array_one = ["A", "B", "C"]
array_two = ["A", "C", "A"]

array_one.select.each_with_index { |item, index| 
  array_two[index] != item 
} => #B and C

答案 1 :(得分:4)

您可以使用zip合并两个数组,并计算两个值相等的内部数组。

arr1 = [1,2,3]
arr2 = [1,5,6]

arr1.zip(arr2)             #=> [[1, 1], [2, 5], [3, 6]]
    .count {|a, b| a == b} #=> 1

另一种方法是只迭代两个数组并运行一个计数器

count = 0

(0...arr1.length).each do |idx|
  count += 1 if arr1[idx] == arr2[idx]
end

当然,两者都假设两个数组的长度相同。

(0...arr1.length)0 to arr1.length-1相同,...是独占的。

答案 2 :(得分:2)

仅仅因为我喜欢这样的东西,我对解决方案进行了基准测试,只是想分享以防任何人感兴趣(我只是将数组切换到更大的数据以获得更有意义的结果)

require "benchmark/ips"

def method_1(ar_1, ar_2)
  ar = ar_1.zip ar_2

  ar.count { |els| els[0] == els[1]  }
end

def method_2(ar_1, ar_2)
  count = 0
  ar_1.each_with_index { |el, i| count += 1 if el == ar_2[i] }
end

def method_3(ar_1, ar_2)
  count = 0

  (0...ar_1.length).each do |idx|
    count += 1 if ar_1[idx] == ar_2[idx]
  end
end

def method_4(ar_1, ar_2)
  ar_1.zip(ar_2).inject(0) do |memo, (left, right)|
    if left == right
      memo
    else
      memo + 1
    end
  end
end

def method_5(ar_1, ar_2)
  ar_1.select.each_with_index do |item, index|
    ar_2[index] != item
  end
end

Benchmark.ips do |x|
  # ar_1 = ["A", "B", "C"]
  # ar_2 = ["B", "C", "A"]

  ar_1 = (0..1_000_000).to_a.shuffle
  ar_2 = (0..1_000_000).to_a.shuffle

  x.report("zip and count") do |times|
    i = 0
    while i < times
      method_1 ar_1, ar_2
      i += 1
    end
  end

  x.report("each with index") do |times|
    i = 0
    while i < times
      method_2 ar_1, ar_2
      i += 1
    end
  end

  x.report("0..length each") do |times|
    i = 0
    while i < times
      method_3 ar_1, ar_2
      i += 1
    end
  end

  x.report("zip and inject") do |times|
    i = 0
    while i < times
      method_4 ar_1, ar_2
      i += 1
    end
  end

  x.report("select each with index") do |times|
    i = 0
    while i < times
      method_5 ar_1, ar_2
      i += 1
    end
  end

  x.compare!
end

###################################################
# 10_000 elements per array                       #
###################################################
#
# Warming up --------------------------------------
#        zip and count    54.000  i/100ms
#      each with index    92.000  i/100ms
#       0..length each    87.000  i/100ms
#       zip and inject    41.000  i/100ms
# select each with index
#                         82.000  i/100ms
# Calculating -------------------------------------
#        zip and count    545.700  (± 2.6%) i/s -      2.754k in   5.050362s
#      each with index    919.259  (± 3.0%) i/s -      4.600k in   5.008972s
#       0..length each    919.908  (± 1.4%) i/s -      4.611k in   5.013518s
#       zip and inject    413.470  (± 1.7%) i/s -      2.091k in   5.058865s
# select each with index
#                         828.774  (± 3.5%) i/s -      4.182k in   5.053036s
#
# Comparison:
#       0..length each:      919.9 i/s
#      each with index:      919.3 i/s - same-ish: difference falls within error
# select each with index:      828.8 i/s - 1.11x slower
#        zip and count:      545.7 i/s - 1.69x slower
#       zip and inject:      413.5 i/s - 2.22x slower


###################################################
# 1_000_000 elements per array                       #
###################################################
#
# Warming up --------------------------------------
#        zip and count     1.000  i/100ms
#      each with index     1.000  i/100ms
#       0..length each     1.000  i/100ms
#       zip and inject     1.000  i/100ms
# select each with index
#                          1.000  i/100ms
# Calculating -------------------------------------
#        zip and count      5.447  (±18.4%) i/s -     26.000  in   5.088342s
#      each with index      9.292  (± 0.0%) i/s -     47.000  in   5.058805s
#       0..length each      9.104  (± 0.0%) i/s -     46.000  in   5.053701s
#       zip and inject      3.983  (± 0.0%) i/s -     20.000  in   5.042810s
# select each with index
#                           7.777  (±12.9%) i/s -     39.000  in   5.053795s
#
# Comparison:
#      each with index:        9.3 i/s
#       0..length each:        9.1 i/s - 1.02x slower
# select each with index:        7.8 i/s - 1.19x slower
#        zip and count:        5.4 i/s - 1.71x slower
#       zip and inject:        4.0 i/s - 2.33x slower

答案 3 :(得分:1)

@ davidhu2000打败了我,但由于这种方法 略有不同,可能还是值得一提:

array_one = ["A", "B", "C"]
array_two = ["B", "C", "A"]

array_one.zip(array_two).inject(0) { |memo, (left, right)|
  unless left == right
    memo + 1
  else
    memo
  end
} # => 3

答案 4 :(得分:1)

这个怎么样

array_one = ["A", "B", "C"]
array_two = ["A", "C", "A"]

array_one.select.each_with_index { |item, index| 
  array_two[index] != item 
} => #["B", "C"]

答案 5 :(得分:1)

array_one = ["A", "B", "C"]
array_two = ["A", "C", "A"]

enum_two = array_two.to_enum
array_one.select { |s| s != enum_two.next }
  #=> ["B", "C"]