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)
1putln("lower: %t", lower)
putln("upper: %t", upper)- 1
- The examples on this page use {format.putln} for formatted printing.
Output:
lower: {['note'] = "note", ['tip'] = "tip", ['warn'] = "warning"}
1upper: {['note'] = "NOTE", ['tip'] = "TIP", ['warn'] = "WARNING"}- 1
-
We mapped the Lua standard
string.upper(...)method over every value in thelowertable.
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)
putln("phone: %t", phone)
putln("email: %t", email)
putln("combined: %t", combined)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,
1 function(v) return v == 'notice' and "CAREFUL!" or v:upper() end)
putln("lower: %t", lower)
putln("upper: %t", upper)- 1
-
Here, we do something special for the
noticekey.
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] = rvThis 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")
putln("original: %t", original)
putln("reversed: %t", reversed)- 1
-
This string lambda
"|k,v| v,k"reverses the key and value and returns both.
Output:
original: {['note'] = "notice", ['tip'] = "hint", ['warn'] = "warning"}
1reversed: {['hint'] = "tip", ['notice'] = "note", ['warning'] = "warn"}- 1
-
Every key-value pair in
originalis 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'}
putln("admonitions: %t", admonitions)
table.transform(admonitions, string.upper)
putln("admonitions: %t", admonitions)Output:
admonitions: {['note'] = "notice", ['tip'] = "hint", ['warn'] = "warning"}
admonitions: {['note'] = "NOTICE", ['tip'] = "HINT", ['warn'] = "WARNING"}