Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Identify runs on array with ruby

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.

like image 613
Arnaldo Ignacio Gaspar Véjar Avatar asked May 13 '14 20:05

Arnaldo Ignacio Gaspar Véjar


People also ask

How do you check if an item is in an array Ruby?

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.

How do you iterate an array in Ruby?

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.

How can you get the position index of an item in an array Ruby?

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.

How do you use the Find method in Ruby?

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.


2 Answers

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
like image 123
BroiSatse Avatar answered Nov 15 '22 03:11

BroiSatse


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.)

like image 45
Cary Swoveland Avatar answered Nov 15 '22 04:11

Cary Swoveland