Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Lua iterator to array

Tags:

lua

In Lua parlance, is there any syntactic sugar for turning an iterator function into an array (repeated invocations with results stored in ascending indices), perhaps something in the standard library ?

I'm tokenizing a string belonging to a protocol and need to to have positional access to elements at the start of the string, and the end of the string is a variant collection.

The code (specific to my use-case) is as follows, I find it hard to believe that it isn't in the standard library :d

local array_tokenise = function (line)
    local i = 1;
    local array = {};

    for item in string.gmatch(line,"%w+") do
      array[i] = item;
      i = i +1
    end

    return array
  end
like image 617
Hassan Syed Avatar asked Nov 29 '11 19:11

Hassan Syed


2 Answers

There's no standard library function for it. But really, it's pretty trivial to write:

function BuildArray(...)
  local arr = {}
  for v in ... do
    arr[#arr + 1] = v
  end
  return arr
end

local myArr = BuildArray(<iterator function call>)

This will only work if your iterator function returns single elements. If it returns multiple elements, you'd have to do something different.

like image 100
Nicol Bolas Avatar answered Oct 31 '22 23:10

Nicol Bolas


As Nicol Bolas said, there is no standard library function that performs the action you desire.

Here is a utility function that extends the table library:

function table.build(build_fn, iterator_fn, state, ...)
    build_fn = (
            build_fn
        or  function(arg)
                return arg
            end
    )
    local res, res_i = {}, 1
    local vars = {...}
    while true do
        vars = {iterator_fn(state, vars[1])}
        if vars[1] == nil then break end
        --build_fn(unpack(vars)) -- see https://web.archive.org/web/20120708033619/http://trac.caspring.org/wiki/LuaPerformance : TEST 3
        res[res_i] = build_fn(vars)
        res_i = res_i+1
    end
    return res
end

Here is some example code demonstrating usage:

require"stringify"

local t1 = {4, 5, 6, {"crazy cake!"}}
local t2 = {a = "x", b = "y", c = "z"}
print(stringify(table.build(nil, pairs(t1))))
print(stringify(table.build(nil, pairs(t2))))
print(stringify(table.build(
        function(arg) -- arg[1] = k, arg[2] = v
            return tostring(arg[1]).." = "..tostring(arg[2])
        end
    ,   pairs(t1)
)))

local poetry = [[
    Roses are red, violets are blue.
    I like trains, and so do you!
    
    By the way, oranges are orange.
    Also! Geez, I almost forgot...
    Lemons are yellow.
]]
print(stringify(table.build(
        function(arg) -- arg[1] == plant, arg[2] == colour
            return (
                    string.upper(string.sub(arg[1], 1, 1))..string.lower(string.sub(arg[1], 2))
                ..  " is "
                ..  string.upper(arg[2]).."!"
            )
        end
    ,   string.gmatch(poetry, "(%a+)s are (%a+)")
)))

Output:

{
    [1] = {
        [1] = 1,
        [2] = 4,
    },
    [2] = {
        [1] = 2,
        [2] = 5,
    },
    [3] = {
        [1] = 3,
        [2] = 6,
    },
    [4] = {
        [1] = 4,
        [2] = {
            [1] = "crazy cake!",
        },
    },
}
{
    [1] = {
        [1] = "a",
        [2] = "x",
    },
    [2] = {
        [1] = "c",
        [2] = "z",
    },
    [3] = {
        [1] = "b",
        [2] = "y",
    },
}
{
    [1] = "1 = 4",
    [2] = "2 = 5",
    [3] = "3 = 6",
    [4] = "4 = table: 00450BE8",
}
{
    [1] = "Rose is RED!",
    [2] = "Violet is BLUE!",
    [3] = "Orange is ORANGE!",
    [4] = "Lemon is YELLOW!",
}

stringify.lua can be found here

like image 1
Deco Avatar answered Oct 31 '22 22:10

Deco