如果我们有一个数组
array = [1, 1, 0, 0, 2, 3, 0, 0, 0, 3, 3, 3 ]
我们如何识别给定数字的运行(具有相同值的连续数量)? 例如:
run_pattern_for(array, 0) -> 2
run_pattern_for(array, 3) -> 1
run_pattern_for(array, 1) -> 1
run_pattern_for(array, 2) -> 0
没有2的运行,因为没有两个连续的显示。 有一次运行3,因为只有一个将树作为连续数字显示。
答案 0 :(得分:11)
尝试:
class Array
def count_runs(element)
chunk {|n| n}.count {|a,b| a == element && b.length > 1}
end
end
a = [1, 1, 0, 0, 2, 3, 0, 0, 0, 3, 3, 3 ]
a.count_runs 0 #=> 2
a.count_runs 3 #=> 1
a.count_runs 1 #=> 1
a.count_runs 2 #=> 0
答案 1 :(得分:3)
我同意@BroiSatse,Enumerable#chunk应该在这里使用,但我想展示如何使用方法Enumerator#next和{{3}直接使用枚举器来解决这个问题}。
<强>代码强>
def count_em(array)
return [] if array.empty?
h = Hash.new(0)
enum = array.each
loop do
x = enum.next
if x == enum.peek
h[x] += 1
enum.next until (enum.peek != x)
else
h[x] = 0 unless h.key?(x)
end
end
h
end
示例强>
array = [1, 1, 0, 0, 2, 3, 0, 0, 0, 3, 3, 3 ]
count_em(array) #=> {1=>1, 0=>2, 2=>0, 3=>1}
<强>解释强>
假设
array = [1, 1, 1, 0, 2, 2]
h = Hash.new(0)
enum = array.each
#=> #<Enumerator: [1, 1, 1, 0, 2, 2]:each>
x = enum.next #=> 1
enum.peek #=> 1
所以x == enum.peek #=> true
,意味着至少有两个1的运行,所以希望执行:
h[x] += 1 #=> h[1] += 1
表示
h[1] = h[1] + 1
由于h
在等式右侧没有键1
,h[x]
设置为零,因此我们在创建哈希时建立了默认值。因此,哈希h
现在是{ 1=>1 }
。现在我们需要在运行中枚举并丢弃更多的1:
enum.next until (enum.peek != x)
enum.next #=> 1
enum.peek #=> 1
enum.next #=> 1
enum.peek #=> 0
现在回到循环的顶部:
x = enum.next #=> 0
enum.peek #=> 2
自(x == enum.peek) => (0 == 2) => false
和h.key?(x) => false
以来,我们设置了
h[0] = 0
,哈希现在是{ 1=>1, 0=>0 }
。再次回到循环的顶部,
x = enum.next #=> 2
enum.peek #=> 2
从(x == enum.peek) => (2 == 2) => true
开始,我们执行:
h[2] += 1 #=> 1
所以现在h => {1=>1, 0=>0, 2=>1}
。现在我们执行
x = enum.next #=> 2
enum.peek #=> StopIteration: iteration reached an end
例外由Enumerator#peek获救。也就是说,引发StopIteration
错误是摆脱循环的一种方法,导致方法的最后一行被执行并返回:
h #=> {1=>1, 0=>0, 2=>1}
(请注意,此结果与上述示例中的结果不同,因为它适用于不同的array
。)
答案 2 :(得分:2)
Ruby 2.2,在发布此问题大约七个月后发布,它为我们提供了一个在此处有应用的方法,Enumerable#slice_when:
array.slice_when { |i,j| i != j }.each_with_object(Hash.new(0)) { |a,h|
h[a.first] += (a.size > 1) ? 1 : 0 }
#=> {1=>1, 0=>2, 2=>0, 3=>1}
答案 3 :(得分:0)
这是一项简单的任务;我有两种不同的方法:
array = [1, 1, 0, 0, 2, 3, 0, 0, 0, 3, 3, 3 ]
hash = Hash[array.group_by { |e| e }.map{ |k, v| [k, v.size] }]
# => {1=>2, 0=>5, 2=>1, 3=>4}
和
hash = Hash.new{ |h,k| h[k] = 0 }
array.each { |e| hash[e] += 1 }
hash # => {1=>2, 0=>5, 2=>1, 3=>4}
一旦你有了哈希,剩下的就很容易了:
hash[0] # => 5
hash[1] # => 2
hash[2] # => 1
hash[3] # => 4
如果您可以请求对数组中不存在的数字进行计数,并希望使用数字响应代替nil
,请使用以下内容:< / p>
Integer(hash[4]) # => 0
Integer(...)
为您将nil转换为0
。
在上面的第一个示例中,group_by
将执行繁重的工作,并导致:
array.group_by { |e| e } # => {1=>[1, 1], 0=>[0, 0, 0, 0, 0], 2=>[2], 3=>[3, 3, 3, 3]}
map
语句只是将数组转换为其大小。