如何" uniq"一个数组,保留每个元素的最后一个副本而不是第一个?

时间:2015-10-03 17:45:23

标签: ruby

调用Array#uniq时,新数组会保留每个副本的第一个

["a", "b", "c", "a"].uniq #=> ["a", "b", "c"]

标准库是否为" uniq"提供了一种干净的方式。一个数组,但保持最后出现重复元素?

e.g:

["b", "c", "a"]

2 个答案:

答案 0 :(得分:9)

您可以通过反转数组,取消它,然后再将其反转为原始顺序来实现此目的:

["a", "b", "c", "a"].reverse.uniq.reverse
#=> ["b", "c", "a"]

答案 1 :(得分:2)

这是另一种方式:

require 'set'

def reverse_uniq(arr)
  s = Set.new
  arr.reverse_each.with_object([]) { |e,a| a.unshift(e) if s.add?(e) }
end

例如:

reverse_uniq [1,2,3,4,3,2,1]
  #=> [4, 3, 2, 1] 

让我们比较大型阵列的速度方法:

require 'fruity'
require 'set'

arr = Array.new(1e6) { rand(1e5) }

compare do 
  re     { s = Set.new; arr.reverse_each.with_object([]) { |e,a|
             a.unshift(e) if s.add?(e) } }
  rur    { arr.reverse.uniq.reverse }
  rurb   { arr.reverse.uniq.reverse! }
  rubrb  { (arr.unshift(arr.first)).reverse.uniq!.reverse! }
  rbubrb { (arr << arr[-1]).reverse!.uniq!.reverse! }
end

Running each test once. Test will take about 27 seconds.
rur is similar to rurb
rurb is similar to rubrb
rubrb is similar to rbubrb
rbubrb is faster than re by 30.000000000000004% ± 10.0%

rubrbrbubrb中的第一位是为了确保:1)uniq!nil时不会返回arr==arr.uniq; 2)返回的数组元素按rur返回的数组排序。

因此,如果内存有限,您可能希望使用rbubrb如果您可以改变阵列,或rubrb如果不能,则只需使用rur