If we have an array
array = [1, 1, 0, 0, 2, 3, 0, 0, 0, 3, 3, 3 ]
How can we identify the run (amount of consecutive numbers with same value) of a given number? By example:
run_pattern_for(array, 0) -> 2
run_pattern_for(array, 3) -> 1
run_pattern_for(array, 1) -> 1
run_pattern_for(array, 2) -> 0
There are no runs for 2 because there are no consecutive apparitions of two. There are one run for 3 because there are only one apparition with the tree as consecutive numbers.
This is another way to do this: use the Array#index method. It returns the index of the first occurrence of the element in the array. This returns the index of the first word in the array that contains the letter 'o'. index still iterates over the array, it just returns the value of the element.
Ruby each Method To iterate over an array in Ruby, use the . each method. It is preferred over a for loop as it is guaranteed to iterate through each element of an array.
Ruby | Array class find_index() operation Array#find_index() : find_index() is a Array class method which returns the index of the first array. If a block is given instead of an argument, returns the index of the first object for which the block returns true.
The find() of enumerable is an inbuilt method in Ruby returns the first element which satisfies the given condition in the block. If there is no block, then it returns the enumerator itself. Parameters: The function takes the block according to which the first which satisfies is to be returned.
try:
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
I agree with @BroiSatse that Enumerable#chunk should be used here, but I would like to show how an enumerator could be employed directly to solve this problem, using the methods Enumerator#next and Enumerator#peek.
Code
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
Example
array = [1, 1, 0, 0, 2, 3, 0, 0, 0, 3, 3, 3 ]
count_em(array) #=> {1=>1, 0=>2, 2=>0, 3=>1}
Explanation
Suppose
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
so x == enum.peek #=> true
, meaning there is a run of at least two 1's, so wish execute:
h[x] += 1 #=> h[1] += 1
which means
h[1] = h[1] + 1
Since h
does not have a key 1
, h[x]
on the right side of the equality set to zero, the default value we established when creating the hash. Therefore, the hash h
is now { 1=>1 }
. Now we want need to enumerate and discard any more 1's in the run:
enum.next until (enum.peek != x)
enum.next #=> 1
enum.peek #=> 1
enum.next #=> 1
enum.peek #=> 0
Now go back to the top of the loop:
x = enum.next #=> 0
enum.peek #=> 2
Since (x == enum.peek) => (0 == 2) => false
, and h.key?(x) => false
, we set
h[0] = 0
and the hash is now { 1=>1, 0=>0 }
. Returning again to the top of the loop,
x = enum.next #=> 2
enum.peek #=> 2
Since (x == enum.peek) => (2 == 2) => true
, we execute:
h[2] += 1 #=> 1
so now h => {1=>1, 0=>0, 2=>1}
. Now when we execute
x = enum.next #=> 2
enum.peek #=> StopIteration: iteration reached an end
The exception is rescued by Kernel#loop. That is, raising a StopIteration
error is one way to break out of the loop, causing the last line of the method to be executed and returned:
h #=> {1=>1, 0=>0, 2=>1}
(Note this result differs from that in the example above because it is for a different array
.)
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With