scarsam
scarsam

Reputation: 346

Iterate over an array n items at a time and continue the iteration

I'm trying to build a CLI. I want to print the name of each object stored in my array. This is how my array looks like:

my_arr = [#<MyObject::Obj:0x007f828daf33b0>, #<MyObject::Obj:0x007f358daf33b0>..]

Instead of showing a long list at once, I want the user to take action to display 200/1000 names at a time. This is my code:

my_arr.each_with_index do |my_obj, index|
  puts "#{index} #{my_obj.name}"
end

I'm thinking to use case statement to build the user interaction part, but having issues finding ways to split my Array. How can I start iterating on my Array, break out from the iteration (ask for user input) and after that continue to iterate where I left off?

Upvotes: 0

Views: 145

Answers (3)

Sagar Pandya
Sagar Pandya

Reputation: 9497

Use an enumerator to enable a stop/continue process:

arr = ('a'..'j').to_a
 #=> ["a", "b", "c", "d", "e", "f", "g", "h", "i", "j"]
enum = arr.to_enum

def taker n, enum
  n.times.with_object [] { |_, o| o << enum.next }
end

Then take how ever many elements you want...

taker 2, enum
 #=> ["a", "b"]

...and pick up from where you left off:

taker 3, enum
 #=> ["c", "d", "e"]
taker 1, enum
 #=> ["f"]

How you print the output and/or user-prompt is up to you.

Upvotes: 0

Simple Lime
Simple Lime

Reputation: 11035

Ruby has an Enumerable#each_slice method that will give you an array in groups, which could allow you to do something similar to:

my_arr = my_arr.collect.with_index do |my_obj, index|
  "#{index} #{my_obj.name}" # do this all the way up here to get the original index
end.each_slice(5)

length = my_arr.size - 1 # how many groups do we need to display
my_arr.each.with_index do |group, index|
  puts group.join("\n") # show the group, which is already in the desired format

  if index < length # if there are more groups to show,
                    # show a message and wait for input
    puts "-- MORE --"
    gets
  end
end

Upvotes: 1

Dust_In_The_Wind
Dust_In_The_Wind

Reputation: 3692

You can use break and next. A short demo -

def foo_next(arr)
  arr.each_with_index { |item, index| 
    next if index % 2 == 0
    puts item
  }
end


def foo_break(arr)
  arr.each_with_index { |item, index| 
    puts item
    break if index % 2 == 0
  }
end

nums = (1..10).to_a

foo_next(nums) # prints 2 4 6 8 10

foo_break(nums) # prints 1

Upvotes: 0

Related Questions