table module

Extends the Lua 5.2 table library, adding more capabilities and functions.

NOTE: Several functions in this module will only work with arrays, which are tables with sequentially numbered keys. All table functions will work with arrays as well, but array functions will not work with tables.

Usage

local table = require('__flib__.table')

Functions

deep_compare(tbl1, tbl2) Recursively compare two tables for inner equality.
deep_copy(tbl) Recursively copy the contents of a table into a new table.
deep_merge(tables) Recursively merge two or more tables.
for_each(tbl, callback) Call the given function for each item in the table, abort if the function returns truthy.
for_n_of(tbl, from_k, n, callback[, _next]) Call the given function on a set number of items in a table, returning the next starting key and the results of the callback.
filter(tbl, filter[, array_insert]) Create a filtered version of a table based on the results of a filter function.
invert(tbl) Invert the given table such that [value] = key, returning a new table.
map(tbl, mapper) Create a transformed table using the output of a mapper function.
reduce(arr, reducer[, initial_value]) “Reduce” an array’s values into a single output value, using the results of a reducer function.
shallow_copy(tbl, use_rawset) Shallowly copy the contents of a table into a new table.
size(tbl) Retrieve the size of a table.
slice(arr[, start=1][, stop=#arr]) Retrieve a shallow copy of a portion of an array, selected from start to end inclusive.
splice(arr[, start=1][, stop=#arr]) Extract a portion of an array, selected from start to end inclusive.

Functions

# deep_compare(tbl1, tbl2)

Recursively compare two tables for inner equality.

Does not compare metatables.

Parameters: Returns:
  • (boolean) If the tables are the same.
# deep_copy(tbl)

Recursively copy the contents of a table into a new table.

Does not create new copies of Factorio objects.

Parameters:
  • tbl : (table) The table to make a copy of.
Returns:
  • (table) The copied table.
# deep_merge(tables)

Recursively merge two or more tables.

Values from earlier tables are overwritten by values from later tables, unless both values are tables, in which case they are recursively merged.

Non-merged tables are deep-copied, so the result is brand-new.

Parameters:
  • tables : (array) An array of tables to merge.
Returns:
  • (table) The merged tables.
Usage:
local tbl = {foo = "bar"}
log(tbl.foo) -- logs "bar"
log (tbl.bar) -- errors (key is nil)
tbl = table.merge{tbl, {foo = "baz", set = 3}}
log(tbl.foo) -- logs "baz"
log(tbl.bar) -- logs "3"
# for_each(tbl, callback)

Call the given function for each item in the table, abort if the function returns truthy.

Calls callback(value, key, tbl) for each item in the table, and immediately ceases iteration if the callback returns a truthy value.

Parameters:
  • tbl : (table)
  • callback : (function) Receives value, key, and tbl as parameters.
Returns:
  • (boolean) Whether the callback returned true for any one item, and thus halted iteration.
Usage:
local tbl = {1, 2, 3, 4, 5}
-- run a function for each item (identical to a standard FOR loop)
table.for_each(tbl, function(v) game.print(v) end)
-- determine if any value in the table passes the test
local value_is_even = table.for_each(tbl, function(v) return v % 2 == 0 end)
-- determine if ALL values in the table pass the test (invert the test result and function return)
local all_values_less_than_six = not table.for_each(tbl, function(v) return not (v < 6) end)
# for_n_of(tbl, from_k, n, callback[, _next])

Call the given function on a set number of items in a table, returning the next starting key and the results of the callback.

Calls callback(value, key) over n items from tbl, starting after from_k.

The first return value of each invocation of callback will be collected and returned in a table keyed by the current item’s key.

The second return value of callback is a flag requesting deletion of the current item.

DO NOT delete entires from tbl from within callback, this will break the iteration. Use the deletion flag return instead.

Parameters:
  • tbl : (table) The table to iterate over.
  • from_k : (any or nil) The key to start iteration at, or nil to start at the beginning of tbl. If the key does not exist in tbl, it will be treated as nil.
  • n : (uint) The number of items to iterate.
  • callback : (function) Receives value and key as parameters.
  • _next : (function) A custom next() function. If not provided, the default next() will be used. (optional)
Returns:
  • (any or nil) Where the iteration ended. Can be any valid table key, or nil if the end of tbl was reached. Pass this as from_k in the next call to for_n_of for tbl.
  • (table) The results compiled from the first return of callback.
Usage:
local extremely_large_table = {
  [1000] = 1,
  [999] = 2,
  [998] = 3,
  ...,
  [2] = 999,
  [1] = 1000,
}
event.on_tick(function()
  global.from_k = table.for_n_of(extremely_large_table, global.from_k, 10, function(v) game.print(v) end)
end)
# filter(tbl, filter[, array_insert])

Create a filtered version of a table based on the results of a filter function.

Calls filter(value, key, tbl) on each element in the table, returning a new table with only pairs for which filter returned a truthy value.

Parameters:
  • tbl : (table)
  • filter : (function) Takes in value, key, and tbl as parameters.
  • array_insert : (boolean) If true, the result will be constructed as an array of values that matched the filter. Key references will be lost. (optional)
Returns:
  • (table) A new table containing only the filtered values.
Usage:
local tbl = {1, 2, 3, 4, 5, 6}
local just_evens = table.filter(tbl, function(v) return v % 2 == 0 end) -- {[2] = 2, [4] = 4, [6] = 6}
local just_evens_arr = table.filter(tbl, function(v) return v % 2 == 0 end, true) -- {2, 4, 6}
# invert(tbl)

Invert the given table such that [value] = key, returning a new table.

Non-unique values are overwritten based on the ordering from pairs().

Parameters: Returns:
  • (table) The inverted table.
Usage:
local tbl = {"foo", "bar", "baz", set = "baz"}
local inverted = table.invert(tbl) -- {foo = 1, bar = 2, baz = "set"}
# map(tbl, mapper)

Create a transformed table using the output of a mapper function.

Calls mapper(value, key, tbl) on each element in the table, using the return as the new value for the key.

Parameters:
  • tbl : (table)
  • mapper : (function) Takes in value, key, and tbl as parameters.
Returns:
  • (table) A new table containing the transformed values.
Usage:
local tbl = {1, 2, 3, 4, 5}
local tbl_times_ten = table.map(tbl, function(v) return v * 10 end) -- {10, 20, 30, 40, 50}
# reduce(arr, reducer[, initial_value])

“Reduce” an array’s values into a single output value, using the results of a reducer function.

Calls reducer(accumulator, value, index) on each element in the array, returning a single accumulated output value.

Parameters:
  • arr : (array)
  • reducer : (function)
  • initial_value : (any) The initial value for the accumulator. If not provided or is falsy, the first value in the array will be used as the initial accumulator value and skipped as index. Calling reduce() on an empty array without an initial_value will cause a crash. (optional)
Returns:
  • (any) The accumulated value.
Usage:
local tbl = {10, 20, 30, 40, 50}
local sum = table.reduce(tbl, function(acc, v) return acc + v end)
local sum_minus_ten = table.reduce(tbl, function(acc, v) return acc + v end, -10)
# shallow_copy(tbl, use_rawset)

Shallowly copy the contents of a table into a new table.

The parent table will have a new table reference, but any subtables within it will still have the same table reference.

Does not copy metatables.

Parameters:
  • tbl : (table)
  • use_rawset : (boolean) Use rawset to set the values (ignores .__index metamethod).
Returns:
  • (table) The copied table.
# size(tbl)

Retrieve the size of a table.

Uses Factorio’s built-in table_size function.

Parameters: Returns:
  • (uint) Size of the table.
# slice(arr[, start=1][, stop=#arr])

Retrieve a shallow copy of a portion of an array, selected from start to end inclusive.

The original array will not be modified.

Parameters:
  • arr : (array)
  • start : (int) (default: 1)
  • stop : (int) Stop at this index. If negative, will stop n items from the end of the array. (default: #arr)
Returns:
  • (array) A new array with the copied values.
Usage:
local arr = {10, 20, 30, 40, 50, 60, 70, 80, 90}
local sliced = table.slice(arr, 3, 7) -- {30, 40, 50, 60, 70}
log(serpent.line(arr)) -- {10, 20, 30, 40, 50, 60, 70, 80, 90} (unchanged)
# splice(arr[, start=1][, stop=#arr])

Extract a portion of an array, selected from start to end inclusive.

The original array will be modified.

Parameters:
  • arr : (array)
  • start : (int) (default: 1)
  • stop : (int) Stop at this index. If negative, will stop n items from the end of the array. (default: #arr)
Returns:
  • (array) A new array with the extracted values.
Usage:
local arr = {10, 20, 30, 40, 50, 60, 70, 80, 90}
local spliced = table.splice(arr, 3, 7) -- {30, 40, 50, 60, 70}
log(serpent.line(arr)) -- {10, 20, 80, 90} (values were removed)