问题
I'm trying to count the differences between two arrays where the order DOES matter. For example:
array_one = ["A", "B", "C"]
array_two = ["B", "C", "A"]
This would yield 3 differences because:
array_one[0] != array_two[0]
array_one[1] != array_two[1]
array_one[2] != array_two[2]
Another example:
array_one = ["Z", "X", "Y"]
array_two = ["Z", "W", "Y"]
This would yield 1 because:
array_one[0] == array_two[0]
array_one[1] != array_two[1]
array_one[2] == array_two[2]
Any suggestions greatly appreciated.
回答1:
how about this
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
回答2:
You can merge the two arrays using zip
, and count the inside array where the two values are equal.
arr1 = [1,2,3]
arr2 = [1,5,6]
arr1.zip(arr2) #=> [[1, 1], [2, 5], [3, 6]]
.count {|a, b| a == b} #=> 1
Another way is the just iterate through both array and run a counter
count = 0
(0...arr1.length).each do |idx|
count += 1 if arr1[idx] == arr2[idx]
end
Of course, both assume the two arrays are the same length.
(0...arr1.length)
is the same as 0 to arr1.length-1
, the ...
is exclusive.
回答3:
Just because I like stuff like this, I benchmarked the solutions, just wanted to share in case anyone is interested (I just switched the array to a bigger one to get more meaningful results)
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
回答4:
@davidhu2000 beat me to it, but as this approach is slightly different, it might still be worth mentioning:
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
回答5:
how about this
array_one = ["A", "B", "C"]
array_two = ["A", "C", "A"]
array_one.select.each_with_index { |item, index|
array_two[index] != item
} => #["B", "C"]
回答6:
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"]
来源:https://stackoverflow.com/questions/39442577/ruby-how-to-find-difference-between-2-arrays-order-matters