下面的方法应该采用数组a
并返回第二个索引值最低的重复整数。该数组仅包含1和a.length
之间的整数。通过这个例子,
firstDuplicate([1,2,3,2,4,5,1])
该方法返回2
。
def firstDuplicate(a)
num = 1
big_num_array = []
a.length.times do
num_array = []
if a.include?(num)
num_array.push(a.index(num))
a[a.index(num)] = "x"
if a.include?(num)
num_array.unshift(a.index(num))
num_array.push(num)
end
big_num_array.push(num_array) if num_array.length == 3
end
num += 1
end
if big_num_array.length > 0
big_num_array.sort![0][2]
else
-1
end
end
代码可以工作,但似乎比必要的时间长,并且运行速度不够快。我正在寻找重构的方法。
答案 0 :(得分:3)
您可以随时计算条目,并在您再次找到某个内容时使用Enumerable#find
停止迭代:
h = { }
a.find do |e|
h[e] = h[e].to_i + 1 # The `to_i` converts `nil` to zero without a bunch of noise.
h[e] == 2
end
你也可以说:
h = Hash.new(0) # to auto-vivify with zeros
a.find do |e|
h[e] += 1
h[e] == 2
end
或使用Hash#fetch
使用默认值:
h = { }
a.find do |e|
h[e] = h.fetch(e, 0) + 1
h[e] == 2
end
find
会在找到构成该块true
的元素后立即停止,因此这应该是合理有效的。
答案 1 :(得分:3)
这有两种方法可以很简单地完成。
使用
require 'set'
def first_dup(arr)
st = Set.new
arr.find { |e| st.add?(e).nil? }
end
first_dup [1,2,3,2,4,5,4,1,4]
#=> 2
first_dup [1,2,3,4,5]
#=> nil
请参阅Set#add?。
使用Array#difference
def first_dup(arr)
arr.difference(arr.uniq).first
end
first_dup [1,2,3,2,4,5,4,1,4]
#=> 2
first_dup [1,2,3,4,5]
#=> nil
我发现Array#difference
足够有用proposed it be added to the Ruby core(但它似乎并没有获得牵引力)。它如下:
class Array
def difference(other)
h = other.each_with_object(Hash.new(0)) { |e,h| h[e] += 1 }
reject { |e| h[e] > 0 && h[e] -= 1 }
end
end
如链接所述,它与Array#-的区别如下:
a = [1,2,2,3,3,2,2]
b = [2,2,3]
a - b
#=> [1]
a.difference(b)
#=> [1,3,2,2]
即difference
"删除" 2
中a
2
b
中3
一个a
(类似于a
),保留arr = [1,2,3,2,4,5,4,1,4]
a = arr.uniq
#=> [1,2,3,4,5]
b = arr.difference(a)
#=> [2, 4, 1, 4]
b.first
#=> 2
左侧的顺序}。但是,iFrame
并未发生变异。
上面针对本问题给出的示例中的步骤如下。
.load()
答案 2 :(得分:2)
如果您正在寻找超级性能,ruby可能不是最佳选择语言。如果您正在寻找可读性,请转到:
[1,2,3,2,4,5,1].
map. # or each (less readable, probably faster)
with_index.
group_by(&:shift). # or group_by(&:first)
min_by { |v, a| a[1] && a[1].last || Float::INFINITY }.
first
#⇒ 2