lua-users home
lua-l archive

[Date Prev][Date Next][Thread Prev][Thread Next] [Date Index] [Thread Index]


> I have a function I would like to optimize (yes, I've done profiling).
> it transforms string like "3-7" into "3,4,5,6,7".

Try this:

function transform(str)
  local _, _, from, to = string.find(str, "^(%d+)%-(%d+)$")
  assert(from, "Transform needs a string in the format i-j")
  local n1, n2 = tonumber(from), tonumber(to)
  if n1 >= n2 then return from end
  local template = from .. string.rep(", ", n2 - n1)
  return (string.gsub(template, " ", function() n1 = n1 + 1; return n1 
end))
end

Philippe had a good idea about memoising results; the above can be 
improved
(slightly) by memoising the template string. (It only helps on largish 
ranges.)

-- A useful tool:

function memoise(fn)
  return setmetatable({}, {
    __index = function(t, k)
                local rv = fn(k)
                t[k] = rv
                return rv
              end
  })
end

do
  local function make_template(k)
    return " " .. string.rep(", ", k)
  end

  local template = memoise(make_template)

  function transform2(str)
    local _, _, from, to = string.find(str, "^(%d+)%-(%d+)$")
    assert(from, "Transform needs a string in the format i-j")
    local n1, n2 = tonumber(from), tonumber(to)
    if n1 >= n2 then return from end
    return (string.gsub(template[n2 - n1], " ",
            function() local rv = n1; n1 = n1 + 1; return rv end))
  end
end

The test for n1 >= n2 is actually unnecessary, but that counts on a
particular behaviour of string.rep. In fact, the conversion of from
and to to numbers is also unnecessary (if the comparison is removed),
because it will happen automatically. So making those changes, we
could reduce the code to the following: (shorter, if not faster)

do
  local function make_template(k)
    return " " .. string.rep(", ", k)
  end

  local template = memoise(make_template)

  function transform3(str)
    local _, _, from, to = string.find(str, "^(%d+)%-(%d+)$")
    assert(from, "Transform needs a string in the format i-j")
    return (string.gsub(template[to - from], " ",
            function() local rv = from; from = from + 1; return rv end))
  end
end