Lua Tables — Mapping & Transforming
Introduction
If you have imported the lulu.table
module as
require 'lulu.table'
Then you have access to the following methods:
table.map(tbl,fun,...)
Returns a new table, which results from applying fun
to each value in a table.
table.map2(tbl1,tbl2,fun,...)
Returns a new table that results from applying fun
to the values from two tables.
table.kv_map(tbl,fun,...)
Returns a new table, which results from applying fun to a table’s keys and values.
table.transform(tbl,fun,...)
Transform a table in place by applying fun
to each top-level value. This method returns the transformed tbl
and is ready for further processing.
table.map
Classic “functional” method that creates a new table by applying fun
to each value in tbl
.
In this implementation, the function also passes any extra arguments in the call to table.map(tbl,fun,...)
.
If the returned table is the result
, then for each key-value pair k,v
in tbl
, we set:
result[k] = fun(v,...)
Of course, fun
may ignore those extra arguments entirely, and Lua is happy to call a function with multiple arguments, even if it only uses the first one.
Example:
local lower = {warn = 'warning', note = 'notice', tip = 'hint'}
local upper = table.map(lower, string.upper)
1("lower: %t", lower)
putln("upper: %t", upper) putln
- 1
- The examples on this page use {format.putln} for formatted printing.
Output:
lower: {['note'] = "note", ['tip'] = "tip", ['warn'] = "warning"}1 upper: {['note'] = "NOTE", ['tip'] = "TIP", ['warn'] = "WARNING"}
- 1
-
We mapped the Lua standard
string.upper(...)
method over every value in thelower
table.
table.map2
Creates a new table by applying fun
to pairs of values taken from two input tables. table.map2(tbl1,tbl2,fun,....)
iterates through the keys k
in tbl1
and if there is a corresponding key in tbl2
then it sets:
result[k] = fun(tbl1[k],tbl2[k],...).
Note that the method skips past any keys not present in both the input tables.
Example:
local phone = {mary = '888-888-8888', phil = '888-888-9999'}
local email = {mary = 'mary@gmail.com', phil = 'phil@gmail.com'}
local combined = table.map2(phone, email,
function(v1,v2) return {phone=v1, email=v2} end)
("phone: %t", phone)
putln("email: %t", email)
putln("combined: %t", combined) putln
Output:
phone: {['mary'] = "888-888-8888", ['phil'] = "888-888-9999"}
email: {['mary'] = "mary@gmail.com", ['phil'] = "phil@gmail.com"}
combined: {['mary'] = {['email'] = "mary@gmail.com", ['phone'] = "888-888-8888"}, ['phil'] = {['email'] = "phil@gmail.com", ['phone'] = "888-888-9999"}}
table.kv_map
For this method, fun
is called with at least two arguments. At its simplest, it is similar to the map
function above, and for every key-value pair in tbl
it sets:
result[k] = fun(k,v,...)
This means fun
can do something different depending on k
. Here is an example that uses that feature:
Example: kv_map
with a single output
local lower = {warn = 'warning', note = 'notice', tip = 'hint'}
local upper = table.map(lower,
1function(v) return v == 'notice' and "CAREFUL!" or v:upper() end)
("lower: %t", lower)
putln("upper: %t", upper) putln
- 1
-
Here, we do something special for the
notice
key.
Output:
lower: {['note'] = "notice", ['tip'] = "hint", ['warn'] = "warning"} upper: {['note'] = "CAREFUL!", ['tip'] = "HINT", ['warn'] = "WARNING"}
Perhaps more interestingly, the kv_map
method can optionally return two outputs. If it does, we interpret the first as a key and the second as a value for the result
table.
local rk, rv = fun(k,v,...)
result[rk] = rv
This can be very powerful.
Example: kv_map
with two outputs
local original = {warn = 'warning', note = 'notice', tip = 'hint'}
1local reversed = table.kv_map(original, "|k,v| v,k")
("original: %t", original)
putln("reversed: %t", reversed) putln
- 1
-
This string lambda
"|k,v| v,k"
reverses the key and value and returns both.
Output:
original: {['note'] = "notice", ['tip'] = "hint", ['warn'] = "warning"}1 reversed: {['hint'] = "tip", ['notice'] = "note", ['warning'] = "warn"}
- 1
-
Every key-value pair in
original
is now a value-key pair inreversed
.
table.transform
This method is like map
above except that it works in place, so for each key-value pair k,v
in tbl
, we set:
tbl[k] = fun(v,...)
Example:
local admonitions = {warn = 'warning', note = 'notice', tip = 'hint'}
("admonitions: %t", admonitions)
putlntable.transform(admonitions, string.upper)
("admonitions: %t", admonitions) putln
Output:
admonitions: {['note'] = "notice", ['tip'] = "hint", ['warn'] = "warning"} admonitions: {['note'] = "NOTICE", ['tip'] = "HINT", ['warn'] = "WARNING"}