Range Iterator

lua-users home
wiki

Showing revision 9
The range function below returns an iterator that can be used in for loops instead of the basic for i=i,j,k do end syntax. It can be used for example when the two or three parameters of the basic for loop are returned by another function. -- JeromeVuarand

function range(from, to, step)
  step = step or 1
  return function(_, lastvalue)
    local nextvalue = lastvalue + step
    if step > 0 and nextvalue <= to or step < 0 and nextvalue >= to or
       step == 0
    then
      return nextvalue
    end
  end, nil, from - step
end

Example use:

function f() return 10, 0, -1 end

for i in range(f()) do
  print(i)
end

Update #1:

Conditionals may also be moved out of the functions: --DavidManura

function range(from, to, step)
  step = step or 1
  local f =
    step > 0 and
      function(_, lastvalue)
        local nextvalue = lastvalue + step
        if nextvalue <= to then return nextvalue end
      end or
    step < 0 and
      function(_, lastvalue)
        local nextvalue = lastvalue + step
        if nextvalue >= to then return nextvalue end
      end or
      function(_, lastvalue) return lastvalue end
  return f, nil, from - step
end

Update #2:

Here is a version that in addition to treating step as optional and optimizing the inner conditional checks, allows 1 argument calls:

-- range(a) returns an iterator from 1 to a (step = 1)
-- range(a, b) returns an iterator from a to b (step = 1)
-- range(a, b, step) returns an iterator from a to b, counting by step.
function range(a, b, step)
  if not b then
    b = a
    a = 1
  end
  step = step or 1
  local f =
    step > 0 and
      function(_, lastvalue)
        local nextvalue = lastvalue + step
        if nextvalue <= b then return nextvalue end
      end or
    step < 0 and
      function(_, lastvalue)
        local nextvalue = lastvalue + step
        if nextvalue >= b then return nextvalue end
      end or
      function(_, lastvalue) return lastvalue end
  return f, nil, a - step
end

This allows for a more compact form for simple upwards counting:
-- Prints the range of numbers 1 to 10 inclusive.
for i in range(10) do
  print(i)
end

RecentChanges · preferences
edit · history · current revision
Edited June 21, 2010 5:40 pm GMT (diff)