鉴于这些数组,如何在保持数组中的第四个或第五个的同时删除三次出现的值?
[1,5,1,1,1] # => [1,5]
[3,3,3,2,3] # => [3,2]
[3,4,5,3,3] # => [4,5]
[1,1,1,1,1] # => [1,1]
[1,2,2,4,5] # => [1,2,2,4,5]
这是我尝试过的:
array = [1,5,1,1,1]
top3 = array.select { |x| array.count(x) >= 3 }[0..2]
last2 = array - top3
这种策略(和类似的)似乎只有三个重复但不是四个或五个时才有用。这个问题有优雅的解决方案吗?
更新:谢谢你的惊人答案。作为一个开始的rubyist,我从分析每个响应中学到了很多东西。我的问题来自于对一个骰子计划的Ruby Koan挑战。这是我用Abdo的建议实现的完整解决方案。我确信有更有效的方法来实现该程序:)
def score(dice)
a,b,c,d,e = dice
array = [a,b,c,d,e]
total = 0
triples = array.select {|x| array.count(x) >= 3}[0..2]
singles = array.group_by{|i| i}.values.map{ |a|
a.length > 2 ? a[0, a.length - 3] : a
}.inject([], :+)
# Calculate values for triples
# 1 * 3 = 1000pts
# 2 * 3 = 200pts
# 3 * 3 = 300pts
# 4 * 3 = 400pts
# 5 * 3 = 500pts
# 6 * 3 = 600pts
case triples[0]
when 1 then total += triples[0]*1000
when (2..6) then total += triples[0]*100
end
# Calculate values for singles:
# 1s = 100pts each
# 5s = 50pts each
singles.include? (1) ? singles.select {|x| x == 1 }.each {|x| total += x*100 } : total
singles.include? (5) ? singles.select {|x| x == 5 }.each {|x| total += x*10 } : total
return total
end
puts score([5,1,1, 5, 6]) # 300 points
puts score([]) # 0 points
puts score([1,1,1,5,1]) # 1150 points
puts score([2,3,4,6,2]) # 0 points
puts score([3,4,5,3,3]) # 350 points
puts score([1,5,1,2,4]) # 250 points
答案 0 :(得分:2)
array = [1,5,1,1,1]
occurrence = {}
array.select do|a|
if(array.count(a) > 3)
occurrence[a] ||= []
occurrence[a] << a
occurrence[a].count > 3
else
true
end
end
PS:此解决方案保留原始数组中元素的顺序
答案 1 :(得分:2)
当数组大小很大时,这是一个更快的解决方案: (我避免使用count,因为它会在内部循环中循环遍历数组)
arr.inject({}) {
|h, i| h[i] ||= 0; h[i] += 1; h
}.collect_concat {|k,v| [k] * (v > 2 ? v - 3 : v) }
这是与其他工作解决方案的果味比较:
arr = 1000.times.collect { rand(100) }.shuffle
require 'fruity'
compare do
vimsha {
occurrence = {};
arr.select do|a|
if(arr.count(a) > 3)
occurrence[a] ||= []
occurrence[a] << a
occurrence[a].count > 3
else
true
end
end
}
caryswoveland {
arr.uniq.reduce([]) {|a,e| a + [e]*((cnt=arr.count(e)) > 2 ? cnt-3 : cnt)}
}
aruprakshit {
num_to_del = arr.find { |e| arr.count(e) >= 3 }
if !num_to_del.nil?
3.times do
ind = arr.index { |e| e == num_to_del }
arr.delete_at(ind)
end
end
arr
}
# edited as suggested by @CarySwoveland
abdo {
arr.each_with_object(Hash.new {|h,k| h[k]=[]}) {|i,h| h[i] += 1
}.collect_concat { |k,v| [k] * (v > 2 ? v - 3 : v) }
}
broisatse {
arr.group_by{|i| i}.values.map{ |a|
a.length > 2 ? a[0, a.length - 3] : a
}.inject([], :+)
}
end
以下是比较结果:
Running each test 64 times. Test will take about 48 seconds.
broisatse is faster than abdo by 30.000000000000004% ± 10.0%
abdo is faster than aruprakshit by 4x ± 1.0 (results differ: ...)
aruprakshit is similar to caryswoveland (results differ: ...)
caryswoveland is similar to vimsha (results differ: ...)
注意:我在方法之外使用了@ aruprakshit的代码,所以我们不会在方法调用本身中浪费时间。
当阵列的大小进一步增加时:
arr = 1000.times.collect { rand(1000) }.shuffle
我们得到:
abdo is faster than broisatse by 3x ± 1.0
broisatse is faster than aruprakshit by 6x ± 10.0
aruprakshit is faster than caryswoveland by 2x ± 1.0
caryswoveland is similar to vimsha
答案 2 :(得分:1)
另一种方式,假设不需要保留订单(这与提问者的评论一致):
array = [1,2,4,1,2,1,2,1,1,4]
array.uniq.reduce([]) {|a,e| a + [e]*((cnt=array.count(e)) > 2 ? cnt-3 : cnt)}
#=> [1, 1, 4, 4]
答案 3 :(得分:0)
尝试类似:
a.group_by{|i| i}.values.map{|a| a[0, a.length % 3]}.inject([], :+)
这将从阵列中删除所有三元组。如果您只想删除第一个三元组,请执行以下操作:
a.group_by{|i| i}.values.map{|a| a.length > 2 ? a[0, a.length - 3] : a }.inject([], :+)
注意:这可能会破坏数组的顺序:
[1,2,1,2,3] #=> [1,1,2,2,3]
如果您需要保留订单,请告诉我,如果需要,如果超过三个,则需要删除哪些元素,例如:该怎么说:[1,1,2,1,1,]
- [1,2]
或[2,1]
?
答案 4 :(得分:0)
x.group_by{|i| i }.values.select{|a| a.size >= 3 }.each{|a| c=[3,a.size].min; x.delete_if{|e| a[0]==e && (c-=1)>=0 } }
它会从[3,a.size].min
所在的输入a[0]
中删除x
次a
次出现,例如[1,1,1,1]
x = [1,2,1,1,1]
答案 5 :(得分:0)
我会这样做:
def del_first_three(a)
num_to_del = a.find { |e| a.count(e) >= 3 }
return a if num_to_del.nil?
3.times do
ind = a.index { |e| e == num_to_del }
a.delete_at(ind)
end
a
end
del_first_three([3,4,5,3,3]) # => [4, 5]
del_first_three([1,5,1,1,1]) # => [5, 1]
del_first_three([1,2,2,4,5]) # => [1, 2, 2, 4, 5]