• Subject: Re: Map and filter without intermediate tables
• From: Geoff Leyland <geoff_leyland@...>
• Date: Thu, 7 Jun 2012 21:19:38 +1200

```On 7/06/2012, at 7:45 PM, joao lobato wrote:

> Your code looks very convoluted.

Yes.  I'd rather it weren't.  Some of it is to get nice features though - what's returned by map is both an iterator and can be called by pairs.

> When I want to iterate over the (i)pairs of a table without
> intermediate tables I use these two guys:
>
> local function map(f,g,t,i)
>  local l = g(t,i)
>  return function()
>    if l == nil then return nil end
>    local c = l
>    l = g(t,l)
>    return f(c)
>  end
> end
>
> local function filter(p,g,t,i)
>  local l = g(t,i)
>  return function()
>    if l == nil then return nil end
>    local c
>    repeat
>      c,l = l,g(t,l)
>    until c == nil or p(c) == true
>    return c
>  end
> end
>
> --
>
> local square = function(n) return n*n end
> local evenp = function(n) return n%2 == 0 end
>
> local t = {} ; for i=1,100 do t[i] = i end
>
> for k,v in map(square, ipairs(t)) do print(k,v) end
> for k,v in filter(evenp, map(square, ipairs(t) do print(k,v) end

This is nice.  I'd avoided closures because FNEW (creating a closure) doesn't get compiled by LuaJIT, but there aren't actually many FNEWs in there.  (I avoided coroutines for a similar reason - yield and resume aren't compiled and there can be plenty of them) and because you can't set a metatable (and hence __pairs) on a function or thread.  But it is easier on the eyes.

Unfortunately, not faster.  But I rewrote filter using a repeat, which is much nicer than while true do, and it got map (but not imap) considerably quicker for luajit.

(By the way, I've updated the gist to take account of Dirk, Steve and your comments)

```