三种解决方案:粗野(#3,初始答案)、更好(#2,第一次编辑)和最佳(#1,@Stefan 答案的变体,第二次编辑)。
a = [:foo, 1, :foo, 0, nil, :bar, "baz", false]
b = [:foo, 1, :foo, 0, true, "baz", false]
c = [:foo,1,:goo]
d = [:goo,1,:new]
注意b
与 OP 的示例略有不同。
除非下面另有说明,否则将通过反转数组、应用common_prefix
然后反转结果来计算公共后缀。
#1
Stefan 的答案的变体,它摆脱了zip
并且map
(并保留了他将一个数组截断为最多另一个数组长度的技术):
def common_prefix(a,b)
a[0,b.size].take_while.with_index { |e,i| e == b[i] }
end
common_prefix(a,b)
#=> [:foo, 1, :foo, 0]
common_prefix(c,d)
#=> []
#2
def common_prefix(a,b)
any, arr = a.zip(b).chunk { |e,f| e==f }.first
any ? arr.map(&:first) : []
end
def common_suffix(a,b)
any, arr = a[a.size-b.size..-1].zip(b).chunk { |e,f| e==f }.to_a.last
any ? arr.map(&:first) : []
end
common_prefix(a,b)
#=> [:foo, 1, :foo, 0]
# Nore: any, arr = a.zip(b).chunk { |e,f| e==f }.to_a
# => [[true, [[:foo, :foo], [1, 1], [:foo, :foo], [0, 0]]],
# [false, [[nil, true], [:bar, :baz], ["baz", false], [false, nil]]]]
common_suffix(a,b)
#=> ["baz", false]
# Note: any, arr = a[a.size-b.size..-1].zip(b).chunk { |e,f| e==f }.to_a
# => [[false, [[1, :foo], [:foo, 1], [0, :foo], [nil, 0], [:bar, true]]],
# [true, [["baz", "baz"], [false, false]]]]
当:first
被发送到枚举器Enumerable#chunk时,枚举器的第一个元素被返回。因此,它的效率应该与使用Enumerable#take_while 相当。
common_prefix(c,d)
#=> []
common_suffix(c,d)
#=> []
#3
def common_prefix(a,b)
a[0,(0..[a.size, b.size].min).max_by { |n| (a[0,n]==b[0,n]) ? n : -1 }]
end
common_prefix(a,b)
#=> [:foo, 1, :foo, 0]
common_prefix(c,d)
#=> []