Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Count how many times a method can be called until it returns nil

Tags:

ruby

Background: I need to determine the number of records in a remote location. The records are sequentially numbered (starting at 0, no gaps) and can only be fetched one by one based on their number.

The method to fetch the records over the network returns a truthy value upon success and a falsey value upon failure. Here'a an example:

fetch_record(0) #=> true (record #0 exists)
fetch_record(1) #=> true (record #1 exists)
fetch_record(2) #=> true (record #2 exists)
fetch_record(3) #=> nil  (no record #3)

I'm trying to find an elegant way to count how many times I can call fetch_record with increasing argument until it returns nil (3 times in the above example).

What I've tried so far

Given this simplified implementation for testing purposes:

def fetch_record(index)
  raise if index > 3 # just to prevent endless loops
  true if index < 3
end

Here are my attempts:

  1. A while loop with an explicit counter variable would obviously work, but I doesn't look very idiomatic:

    i = 0
    i += 1 while fetch_record(i)
    i
    #=> 3
    
  2. I could use step and break with an explicit result value but that looks cumbersome:

    0.step(by: 1).each { |i| break i unless fetch_record(i) }
    #=> 3
    
  3. A lazy enumerator is even worse:

    0.step(by: 1).lazy.map { |i| fetch_record(i) }.take_while(&:itself).count
    #=> 3
    

Is there an easier way to accomplish the above?

like image 221
Stefan Avatar asked Dec 09 '22 00:12

Stefan


2 Answers

Assuming you are free to implement fetch_record the other way round, to return true for inexisting record:

def fetch_record index
  index >= 3
end
(0..Float::INFINITY).detect &method(:fetch_record)
#⇒ 3
like image 102
Aleksei Matiushkin Avatar answered May 18 '23 17:05

Aleksei Matiushkin


take_while anyone?

records = 0.step.take_while{|i| fetch_record(i)}
like image 30
steenslag Avatar answered May 18 '23 18:05

steenslag