lua-users home
lua-l archive

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


Am 19.12.2012 01:26, schrieb Tomas Lundell:
On Wed, Dec 19, 2012 at 2:35 AM, <lua-l-request@lists.lua.org> wrote:

And everything because you want to write:

     map( filter( t, is_odd ), function( _, v ) print( v ) end )

instead of:

     for i,v in ipairs( t ) do
       if is_odd( i ) then
         print( v )
       end
     end


It's maybe a little silly to use a map for side effects - for that you'd
probably want to use a loop.

Why? Because map unfortunately constructs a superfluous table? Let's call the function 'each' like in underscore.js or its Lua equivalent[1] or Ruby (or table.foreachi like in previous Lua versions). If it's silly, it's not only me ...

  [1]: https://github.com/Yonaba/Moses/blob/master/docs/moses.md#each

Assuming you want to actually transform the
values in some way, say to square them, your example might look like this:

local new_table = {}
for i, v in ipairs(t) do
     if is_odd(i) then
         table.insert(new_table, v * v)
     end
end

I can't remember when I've used any of the table.* functions, but in principle, yes.


Which I would write like this:

     local odd_items = ifilter(is_odd, ipairs(t))
     local new_table = imap(function(i, v) return v * v end,
ipairs(odd_items))

Ok, you have the iterators variant of map/filter, at least for the input, but not the output. If I were to use map/filter, I would choose my version[2] with iterator input and output. The example would look like

    local new_t = {}
for _,w in map( function( i, v ) return v * v end, filter( is_odd, ipairs( t ) ) ) do
      new_t[ #new_t+1 ] = w
    end

No need for different map/imap, filter/ifilter variants, and constant memory overhead (two closures and one normal function) compared to Lua's plain generic for loop instead of linear overhead (temporary array + normal function) as in your example. So you are *nearly* as flexible (no break, only one key + one value, no numeric for, can't handle arrays with holes, etc.) and *nearly* as efficient as Lua's for loop with 4 additional public functions (2 in my case). And at first glance I can't even tell which version is shortest.


Note that all functions are flexible in that:

* You can choose whether you iterate using pairs or ipairs (or a custom
iterator)
* You can choose to return either a key-value table or an array (by
choosing map or imap)

/ Tom


Philipp

  [2]:
    do
      local function map_helper( fun, var_1, ... )
        if var_1 ~= nil then
          return var_1, fun( var_1, ... )
        end
      end

      function map( fun, f, s, var )
        return function( st, v )
          return map_helper( fun, f( st, v ) )
        end, s, var
      end
    end

    do
      local function filter_helper( pred, f, s, var_1, ... )
        if var_1 ~= nil then
          if pred( var_1, ... ) then
            return var_1, ...
          else
            return filter_helper( pred, f, s, f( s, var_1 ) )
          end
        end
      end

      function filter( pred, f, s, var )
        return function( st, v )
          return filter_helper( pred, f, st, f( st, v ) )
        end, s, var
      end
    end