Circular grill

I have an array with different number of elements 0..n elements. An example would be:

a = [0,1,2,3,4,5,6,7,8,9]

      

In an iterative process, I would like to move the cursor into the array and cut off the maximum number of elements. If I get to the "end" of the array, it has to start over and select from the beginning:

Something like that:

4.times do |i|
  a.slice(i * 3, 3)
end
# i = 0 => [0,1,2]
# i = 1 => [3,4,5]
# i = 2 => [6,7,8]
# i = 3 => [9,0,1]
# ...

      

However, the last output i = 3

produces [9]

because it .slice

doesn't do exactly what I want.

+3


source to share


4 answers


You can use cycle

:



a.cycle.each_slice(3).take(4)
#=> [[0, 1, 2], [3, 4, 5], [6, 7, 8], [9, 0, 1]]

      

+8


source


You can use Array # rotate and then take the first 3 elements each time:



4.times.each { |i| a.rotate(i*3)[0..2] }
# => [[0, 1, 2], [3, 4, 5], [6, 7, 8], [9, 0, 1]]

      

+2


source


Possible Solution:

4.times { |i| p a.values_at(*(i*3..i*3+2).map {|e| e % 10 }) }
[0, 1, 2]
[3, 4, 5]
[6, 7, 8]
[9, 0, 1]

      

9% 10 = 9, 10% 10 = 0, 11% 10 = 1. So you get the desired result.

+1


source


This may break some code, so be careful.

class Array
  alias_method :old_slice, :slice
  def slice(o, c)
     ret = old_slice(o % size, c)
     if ret.size != c
        ret += old_slice(0, c - ret.size)
     end
     ret
  end
end

a = [0,1,2,3,4,5,6,7,8,9]

4.times do |i|
  p a.slice(i * 3, 3)
end

      

As Stefan points out, it would be better to give this method a different name, or it might even be better to create a CircularArray class.

class CircularArray < Array
  alias_method :straight_slice, :slice
  def slice(o, c)
     ret = straight_slice(o % size, c)
     if ret.size != c
        ret += straight_slice(0, c - ret.size)
     end
     ret
  end
end

      

0


source







All Articles