TableUtil
A collection of helpful table utility functions. Many of these functions are carried over from JavaScript or Python that are not present in Lua.
Tables that only work specifically with arrays or dictionaries are marked as such in the documentation.
Immutability
All functions (except SwapRemove
, SwapRemoveFirstValue
, and Lock
) treat tables as immutable and will return
copies of the given table(s) with the operations performed on the copies.
Functions
Copy
TableUtil.
Copy
(
tbl:
table
,
--
Table to copy
deep:
boolean?
--
Whether or not to perform a deep copy
) →
table
Creates a copy of the given table. By default, a shallow copy is performed. For deep copies, a second boolean argument must be passed to the function.
No cyclical references
Deep copies are not protected against cyclical references. Passing
a table with cyclical references and the deep
parameter set to
true
will result in a stack-overflow.
Sync
TableUtil.
Sync
(
srcTbl:
table
,
--
Source table
templateTbl:
table
--
Template table
) →
table
Synchronizes the srcTbl
based on the templateTbl
. This will make
sure that srcTbl
has all of the same keys as templateTbl
, including
removing keys in srcTbl
that are not present in templateTbl
. This
is a deep operation, so any nested tables will be synchronized as
well.
local template = {kills = 0, deaths = 0, xp = 0}
local data = {kills = 10, experience = 12}
data = TableUtil.Sync(data, template)
print(data) --> {kills = 10, deaths = 0, xp = 0}
Data Loss Warning
This is a two-way sync, so the source table will have data removed that isn't found in the template table. This can be problematic if used for player data, where there might be dynamic data added that isn't in the template.
For player data, use TableUtil.Reconcile
instead.
Reconcile
TableUtil.
Reconcile
(
source:
table
,
template:
table
) →
table
Performs a one-way sync on the source
table against the
template
table. Any keys found in template
that are
not found in source
will be added to source
. This is
useful for syncing player data against data template tables
to ensure players have all the necessary keys, while
maintaining existing keys that may no longer be in the
template.
This is a deep operation, so nested tables will also be properly reconciled.
local template = {kills = 0, deaths = 0, xp = 0}
local data = {kills = 10, abc = 20}
local correctedData = TableUtil.Reconcile(data, template)
print(correctedData) --> {kills = 10, deaths = 0, xp = 0, abc = 20}
SwapRemove
TableUtil.
SwapRemove
(
tbl:
table
,
--
Array
i:
number
--
Index
) →
(
)
Removes index i
in the table by swapping the value at i
with
the last value in the array, and then trimming off the last
value from the array.
This allows removal of the value at i
in O(1)
time, but does
not preserve array ordering. If a value needs to be removed from
an array, but ordering of the array does not matter, using
SwapRemove
is always preferred over table.remove
.
In the following example, we remove "B" at index 2. SwapRemove does this by moving the last value "E" over top of "B", and then trimming off "E" at the end of the array:
local t = {"A", "B", "C", "D", "E"}
TableUtil.SwapRemove(t, 2) -- Remove "B"
print(t) --> {"A", "E", "C", "D"}
Arrays only
This function works on arrays, but not dictionaries.
SwapRemoveFirstValue
TableUtil.
SwapRemoveFirstValue
(
tbl:
table
,
--
Array
v:
any
--
Value to find
) →
number?
Performs table.find(tbl, v)
to find the index of the given
value, and then performs TableUtil.SwapRemove
on that index.
local t = {"A", "B", "C", "D", "E"}
TableUtil.SwapRemoveFirstValue(t, "C")
print(t) --> {"A", "B", "E", "D"}
Arrays only
This function works on arrays, but not dictionaries.
Map
TableUtil.
Map
(
tbl:
table
,
predicate:
(
value:
any
,
key:
any
,
tbl:
table
)
→
newValue:
any
) →
table
Performs a map operation against the given table, which can be used to map new values based on the old values at given keys/indices.
For example:
local t = {A = 10, B = 20, C = 30}
local t2 = TableUtil.Map(t, function(value)
return value * 2
end)
print(t2) --> {A = 20, B = 40, C = 60}
Filter
TableUtil.
Filter
(
tbl:
table
,
predicate:
(
value:
any
,
key:
any
,
tbl:
table
)
→
keep:
boolean
) →
table
Performs a filter operation against the given table, which can be used to filter out unwanted values from the table.
For example:
local t = {A = 10, B = 20, C = 30}
local t2 = TableUtil.Filter(t, function(value, key)
return value > 15
end)
print(t2) --> {B = 40, C = 60}
Reduce
TableUtil.
Reduce
(
tbl:
table
,
predicate:
(
accumulator:
any
,
value:
any
,
index:
any
,
tbl:
table
)
→
result:
any
) →
table
Performs a reduce operation against the given table, which can be used to reduce the table into a single value. This could be used to sum up a table or transform all the values into a compound value of any kind.
For example:
local t = {10, 20, 30, 40}
local result = TableUtil.Reduce(t, function(accum, value)
return accum + value
end)
print(result) --> 100
Assign
TableUtil.
Assign
(
target:
table
,
...:
table
) →
table
Copies all values of the given tables into the target
table.
local t = {A = 10}
local t2 = {B = 20}
local t3 = {C = 30, D = 40}
local newT = TableUtil.Assign(t, t2, t3)
print(newT) --> {A = 10, B = 20, C = 30, D = 40}
Extend
TableUtil.
Extend
(
target:
table
,
extension:
table
) →
table
Extends the target array with the extension array.
local t = {10, 20, 30}
local t2 = {30, 40, 50}
local tNew = TableUtil.Extend(t, t2)
print(tNew) --> {10, 20, 30, 30, 40, 50}
Arrays only
This function works on arrays, but not dictionaries.
Reverse
TableUtil.
Reverse
(
tbl:
table
) →
table
Reverses the array.
local t = {1, 5, 10}
local tReverse = TableUtil.Reverse(t)
print(tReverse) --> {10, 5, 1}
Arrays only
This function works on arrays, but not dictionaries.
Shuffle
Shuffles the table.
local t = {1, 2, 3, 4, 5, 6, 7, 8, 9}
local shuffled = TableUtil.Shuffle(t)
print(shuffled) --> e.g. {9, 4, 6, 7, 3, 1, 5, 8, 2}
Arrays only
This function works on arrays, but not dictionaries.
Sample
Returns a random sample of the table.
local t = {1, 2, 3, 4, 5, 6, 7, 8, 9}
local sample = TableUtil.Sample(t, 3)
print(sample) --> e.g. {6, 2, 5}
Arrays only
This function works on arrays, but not dictionaries.
Flat
TableUtil.
Flat
(
tbl:
table
,
depth:
number?
) →
table
Returns a new table where all sub-arrays have been
bubbled up to the top. The depth at which the scan
is performed is dictated by the depth
parameter,
which is set to 1
by default.
local t = {{10, 20}, {90, 100}, {30, 15}}
local flat = TableUtil.Flat(t)
print(flat) --> {10, 20, 90, 100, 30, 15}
Arrays only
This function works on arrays, but not dictionaries.
FlatMap
TableUtil.
FlatMap
(
tbl:
table
,
predicate:
(
key:
any
,
value:
any
,
tbl:
table
)
→
newValue:
any
) →
table
Calls TableUtil.Map
on the given table and predicate, and then
calls TableUtil.Flat
on the result from the map operation.
local t = {10, 20, 30}
local result = TableUtil.FlatMap(t, function(value)
return {value, value * 2}
end)
print(result) --> {10, 20, 20, 40, 30, 60}
Arrays only
This function works on arrays, but not dictionaries.
Keys
TableUtil.
Keys
(
tbl:
table
) →
table
Returns an array with all the keys in the table.
local t = {A = 10, B = 20, C = 30}
local keys = TableUtil.Keys(t)
print(keys) --> {"A", "B", "C"}
Ordering
The ordering of the keys is never guaranteed. If order is imperative, call
table.sort
on the resulting keys
array.
local keys = TableUtil.Keys(t)
table.sort(keys)
Values
TableUtil.
Values
(
tbl:
table
) →
table
Returns an array with all the values in the table.
local t = {A = 10, B = 20, C = 30}
local values = TableUtil.Values(t)
print(values) --> {10, 20, 30}
Ordering
The ordering of the values is never guaranteed. If order is imperative, call
table.sort
on the resulting values
array.
local values = TableUtil.Values(t)
table.sort(values)
Find
TableUtil.
Find
(
tbl:
table
,
callback:
(
value:
any
,
index:
any
,
tbl:
table
)
→
boolean
) →
(
value:
any?
,
key:
any?
)
Performs a linear scan across the table and calls callback
on
each item in the array. Returns the value and key of the first
pair in which the callback returns true
.
local t = {
{Name = "Bob", Age = 20};
{Name = "Jill", Age = 30};
{Name = "Ann", Age = 25};
}
-- Find first person who has a name starting with J:
local firstPersonWithJ = TableUtil.Find(t, function(person)
return person.Name:sub(1, 1):lower() == "j"
end)
print(firstPersonWithJ) --> {Name = "Jill", Age = 30}
Dictionary Ordering
While Find
can also be used with dictionaries, dictionary ordering is never
guaranteed, and thus the result could be different if there are more
than one possible matches given the data and callback function.
Every
TableUtil.
Every
(
tbl:
table
,
callback:
(
value:
any
,
index:
any
,
tbl:
table
)
→
boolean
) →
boolean
Returns true
if the callback
also returns true
for every
item in the table.
local t = {10, 20, 40, 50, 60}
local allAboveZero = TableUtil.Every(t, function(value)
return value > 0
end)
print("All above zero:", allAboveZero) --> All above zero: true
Some
TableUtil.
Some
(
tbl:
table
,
callback:
(
value:
any
,
index:
any
,
tbl:
table
)
→
boolean
) →
boolean
Returns true
if the callback
also returns true
for at least
one of the items in the table.
local t = {10, 20, 40, 50, 60}
local someBelowTwenty = TableUtil.Some(t, function(value)
return value < 20
end)
print("Some below twenty:", someBelowTwenty) --> Some below twenty: true
Truncate
TableUtil.
Truncate
(
tbl:
table
,
length:
number
) →
table
Returns a new table truncated to the length of length
. Any length
equal or greater than the current length will simply return a
shallow copy of the table.
local t = {10, 20, 30, 40, 50, 60, 70, 80}
local tTruncated = TableUtil.Truncate(t, 3)
print(tTruncated) --> {10, 20, 30}
Zip
TableUtil.
Zip
(
...:
table
) →
(
iter:
(
t:
table
,
k:
any
)
→
(
key:
any?
,
values:
table?
)
,
tbl:
table
,
startIndex:
any?
)
Returns an iterator that can scan through multiple tables at the same time side-by-side, matching against shared keys/indices.
local t1 = {10, 20, 30, 40, 50}
local t2 = {60, 70, 80, 90, 100}
for key,values in TableUtil.Zip(t1, t2) do
print(key, values)
end
--[[
Outputs:
1 {10, 60}
2 {20, 70}
3 {30, 80}
4 {40, 90}
5 {50, 100}
--]]
Lock
TableUtil.
Lock
(
tbl:
table
) →
table
Locks the table using table.freeze
, as well as any
nested tables within the given table. This will lock
the whole deep structure of the table, disallowing any
further modifications.
local tbl = {xyz = {abc = 32}}
tbl.xyz.abc = 28 -- Works fine
TableUtil.Lock(tbl)
tbl.xyz.abc = 64 -- Will throw an error (cannot modify readonly table)
IsEmpty
TableUtil.
IsEmpty
(
tbl:
table
) →
boolean
Returns true
if the given table is empty. This is
simply performed by checking if next(tbl)
is nil
and works for both arrays and dictionaries. This is
useful when needing to check if a table is empty but
not knowing if it is an array or dictionary.
TableUtil.IsEmpty({}) -- true
TableUtil.IsEmpty({"abc"}) -- false
TableUtil.IsEmpty({abc = 32}) -- false
EncodeJSON
TableUtil.
EncodeJSON
(
value:
any
) →
string
Proxy for HttpService:JSONEncode
.
DecodeJSON
TableUtil.
DecodeJSON
(
value:
any
) →
string
Proxy for HttpService:JSONDecode
.