2021-02-18 05:11:25 +01:00
-- Copies the table deeply, including metatables
function table . copy ( t )
local t_type = type ( t )
local copy
if t_type == " table " then
copy = { }
for k , v in next , t , nil do
copy [ table.copy ( k ) ] = table.copy ( v )
end
setmetatable ( copy , table.copy ( getmetatable ( t ) ) )
else
copy = t
end
return copy
end
-- Copies the table shallowly, meaning that tables inside the table will not be created anew, and only be referenced in the copy
function table . shallow_copy ( t )
local copy = { }
for k , v in pairs ( t ) do
copy [ k ] = v
end
return copy
end
-- t = {}
-- table.array(t, 5) -> {1, 2, 3, 4, 5}
function table . array ( t , n )
for i = 1 , n do
table.push ( t , i )
end
return t
end
-- t = {"a", "b", "c", "d"}
-- table.get(t, 1) -> "a"
-- table.get(t, 1, 3) -> {"a", "b", "c"}
-- table.get(t, 2, -1) -> {"b", "c", "d"}
function table . get ( t , i , j )
if i < 0 then i = # t + i + 1 end
if not j then return t [ i ] end
if j < 0 then j = # t + j + 1 end
if i == j then return t [ i ] end
local out = { }
for k = i , j , math.sign ( j - i ) do
table.push ( out , t [ k ] )
end
return out
end
-- t = {"a", "b", "c", "d"}
-- table.set(t, 1, 1) -> {1, "b", "c", "d"}
-- table.set(t, 1, 3, 2) -> {2, 2, 2, "d"}
-- table.set(t, 2, -1, 3) -> {"a", 3, 3, 3}
function table . set ( t , i , j , v )
if i < 0 then i = # t + i + 1 end
if not v then t [ i ] = j ; return t end
if j < 0 then j = # t + j + 1 end
if i == j then t [ i ] = v ; return t end
for k = i , j , math.sign ( j - i ) do
t [ k ] = v
end
return t
end
-- Returns the index of the first instance of value v
-- t = {4, 3, 2, 4, "a", 1, "a"}
-- table.index(t, 4) -> 1
-- table.index(t, "a") -> 5
function table . index ( t , v )
for i , u in ipairs ( t ) do
if u == v then
return i
end
end
end
-- Returns the last value of the table
-- t = {1, 2, 3, 4}
-- table.back(t) -> 4
function table . back ( t )
return t [ # t ]
end
-- Returns the first n values
-- t = {4, 3, 2, 1}
-- table.head(t) -> 4
-- table.head(t, 2) -> {4, 3}
function table . head ( t , n )
local out = { }
for i = 1 , ( n or 1 ) do
table.push ( out , t [ i ] )
end
if # out == 1 then return out [ 1 ]
else return out end
end
-- Returns the last n values
-- t = {5, 4, 3, 2, 1}
-- table.tail(t) -> 1
-- table.tail(t, 2) -> {2, 1}
function table . tail ( t , n )
local out = { }
for i = # t - ( n or # t - 1 ) + 1 , # t do
table.push ( out , t [ i ] )
end
if # out == 1 then return out [ 1 ]
else return out end
end
-- Inserts value at the end of the table
-- t = {1, 2}
-- table.push(t, "a") -> {1, 2, "a"}
function table . push ( t , v )
table.insert ( t , v )
return t
end
-- Removes the first n values and returns them as well as the modified table
-- t = {4, 3, 2, 1}
-- table.shift(t) -> 4, {3, 2, 1}
-- table.shift(t, 3) -> {4, 3, 2}, {1}
function table . shift ( t , n )
local out = { }
for i = 1 , ( n or 1 ) do
table.insert ( out , table.remove ( t , 1 ) )
end
if # out == 1 then return out [ 1 ] , t
else return out , t end
end
-- Inserts values at the start of the table
-- t = {3, 4}
-- table.unshift(t, 1, 2) -> {1, 2, 3, 4}
function table . unshift ( t , ... )
for j , v in ipairs ( { ... } ) do
table.insert ( t , 1 + j - 1 , v )
end
return t
end
-- Removes the last value and returns it as well as the modified table
-- t = {1, 2, 3, 4}
-- table.pop(t) -> 4, {1, 2, 3}
function table . pop ( t )
return table.remove ( t , # t ) , t
end
-- Deletes all instances of value v
-- t = {1, 1, 2, 3, 2, 3, 4, 4}
-- table.delete(t, 1) -> {2, 3, 2, 3, 4, 4}
-- t = {{id = 1}, {id = 1}, {id = 2}}
-- table.delete(t, function(v) return v.id == 1 end) -> {{id = 2}}
function table . delete ( t , v )
if type ( v ) == ' function ' then
for i = # t , 1 , - 1 do
if v ( t [ i ] ) then
table.remove ( t , i )
end
end
else
for i = # t , 1 , - 1 do
if v == t [ i ] then
table.remove ( t , i )
end
end
end
return t
end
-- Deletes the elements in the given range and returns them as well as the modified table
-- t = {1, 2, 3}
-- table.slice(t, 1) -> 1, {2, 3}
-- table.slice(t, 2, -1) -> {2, 3}, 1
function table . slice ( t , i , j )
if i < 0 then i = # t + i + 1 end
if not j then return t [ i ] end
if j < 0 then j = # t + j + 1 end
if i == j then return t [ i ] end
local out = { }
for k = j , i , - math.sign ( j - i ) do
table.insert ( out , table.remove ( t , k ) )
end
if # out == 1 then return out [ 1 ] , t
else return table.reverse ( out ) , t end
end
-- Removes duplicates
-- t = {1, 1, 2, 2, 3, 3}
-- table.unify(t) -> {1, 2, 3}
-- t = {{id = 1}, {id = 1}, {id = 2}}
-- table.unify(t, function(v) return v.id end) -> {{id = 1}, {id = 2}}
function table . unify ( t , f )
if not f then f = function ( v ) return v end end
local seen = { }
for i = # t , 1 , - 1 do
if not seen [ f ( t [ i ] ) ] then
seen [ f ( t [ i ] ) ] = true
else
table.remove ( t , i )
end
end
return t
end
-- Counts the number of elements in the table
-- t = {1, 1, 5, 5, 4, 1, 3, 2, 0, 9, 8, 5, 1, 5, 5, 4, 6}
-- table.count(t, 1) -> 4
-- table.count(t, 5) -> 5
-- table.count(t, 6) -> 1
-- table.count(t, 4) -> 2
function table . count ( t , v )
local n = 0
for i = 1 , # t do
if t [ i ] == v then
n = n + 1
end
end
return n
end
-- Applies function f to all table elements and replaces each element for the value returned by f
function table . map ( t , f , ... )
for k , v in ipairs ( t ) do
t [ k ] = f ( v , k , ... )
end
return t
end
-- Applies function f to all table elements resulting in a single output value
-- t = {1, 2, 3}
-- table.reduce(t, function(memo, v) return memo + v end) -> 6
-- t = {'a', 'b', 'c'}
-- table.reduce(t, function(memo, v) return memo .. v end) -> 'abc'
-- t = {{id = 1}, {id = 2}, {id = 3}}
-- table.reduce(t, function(memo, v) return memo + v.id end, 0) -> 6
-- The memo variable starts as the first argument in the array, but sometimes, as in the last example, that's not the desired functionality.
-- For those cases the third argument comes in handy and can be used to set the initial value of memo directly.
function table . reduce ( t , f , dv , ... )
2021-03-05 08:29:19 +01:00
local memo = dv or t [ 1 ]
2021-03-06 04:53:44 +01:00
for i = 1 , # t do
2021-02-18 05:11:25 +01:00
memo = f ( memo , t [ i ] , i , ... )
end
return memo
end
-- Applies function f to all array elements without changing the array
function table . foreach ( t , f , ... )
for k , v in ipairs ( t ) do
f ( v , k , ... )
end
return t
end
-- Applies function f to all array elements and adds the results to a new array
function table . foreachn ( t , f , ... )
local out = { }
for k , v in ipairs ( t ) do
table.insert ( out , f ( v , k , ... ) )
end
return out
end
-- Applies filter function f which removes all elements that pass the filter and returns them as well as the modified table
-- t = {1, 2, 3, 4}
-- table.reject(t, function(v) return v >= 3 end) -> {3, 4}, {1, 2}
-- table.reject(t, function(v) return v == 1 end) -> 1, {2, 3, 4}
function table . reject ( t , f , ... )
local out = { }
for i = # t , 1 , - 1 do
if f ( t [ i ] , i , ... ) then
table.insert ( out , table.remove ( t , i ) )
end
end
if # out == 1 then return out [ 1 ] , t
else return table.reverse ( out ) , t end
end
-- Applies filter function f which collects all elements that pass the filter and returns them; the original table is not modified
-- t = {1, 2, 3, 4}
-- table.select(t, function(v) return v >= 3 end) -> {3, 4}
-- table.select(t, function(v) return v == 1 end) -> 1
function table . select ( t , f , ... )
local out = { }
for i = 1 , # t do
if f ( t [ i ] , i , ... ) then
table.insert ( out , t [ i ] )
end
end
return out
end
-- Returns true if any values in the table pass the test
function table . any ( t , f , ... )
for i , v in ipairs ( t ) do
if f ( v , i , ... ) then
return true
end
end
end
-- Returns true if all values in the table pass the test
function table . all ( t , f , ... )
for i , v in ipairs ( t ) do
if not f ( v , i , ... ) then
return false
end
end
return true
end
-- Check if table contains value v and return its index
-- If value v is a function instead then it checks according to the check performed by that function
-- t = {4, 3, 2, 1}
-- table.contains(t, 4) -> 1
-- t = {{id = 4}, {id = 3}, {id = 2}, {id = 1}}
-- table.contains(t, function(v) return v.id == 3 end) -> 2
function table . contains ( t , v )
if type ( v ) == " function " then
for i , u in ipairs ( t ) do
if v ( u ) then return i end
end
else
for i , u in ipairs ( t ) do
if u == v then return i end
end
end
end
-- t = {{1, 2}, {3, {4, 5}}, {6, 7}, 8}
-- table.flatten(t) -> {1, 2, 3, 4, 5, 6, 7, 8}
-- table.flatten(t, true) -> {1, 2, 3, {4, 5}, 6, 7, 8}
function table . flatten ( t , shallow )
local out = { }
local u
for k , v in ipairs ( t ) do
if type ( v ) == " table " and getmetatable ( t ) == nil then
u = shallow and v or table.flatten ( v )
for _ , x in ipairs ( u ) do
table.insert ( out , x )
end
else
table.insert ( out , v )
end
end
return out
end
-- t = {1, 2, 3, 4}
-- table.tostring(t) -> '{[1] = 1, [2] = 2, [3] = 3, [4] = 4}'
function table . tostring ( t )
if type ( t ) == " table " then
local str = " { "
for k , v in ipairs ( t ) do
if type ( k ) ~= " number " then k = ' " ' .. k .. ' " ' end
str = str .. " [ " .. k .. " ] = " .. table.tostring ( v ) .. " , "
end
return str : sub ( 1 , - 3 ) .. " } "
else return tostring ( t ) end
end
-- Returns the first n values, same as head
-- t = {4, 3, 2, 1}
-- table.first(t) -> 4
-- table.first(t, 2) -> {4, 3}
function table . first ( t , n )
if n == 1 then return t [ 1 ] end
local out = { }
for i = 1 , ( n or 1 ) do
table.push ( out , t [ i ] )
end
if # out == 1 then return out [ 1 ]
else return out end
end
-- Returns the last n values, same as tail
-- t = {4, 3, 2, 1}
-- table.last(t) -> 1
-- table.last(t, 2) -> {2, 1}
function table . last ( t , n )
if n == 1 then return t [ # t ] end
local out = { }
for i = # t - n + 1 , # t do
table.push ( out , t [ i ] )
end
if # out == 1 then return out [ 1 ]
else return out end
end
-- t = {"a", "b", "c", "d"}
-- table.reverse(t) -> {"d", "c", "b", "a"}
-- table.reverse(t, 2, 3) -> {"a", "c", "b", "d"}
-- table.reverse(t, 2, -1) -> {"a", "d", "c", "b"}
function table . reverse ( t , i , j )
if not i then i = 1 end
if i < 0 then i = # t + i + 1 end
if not j then j = # t end
if j < 0 then j = # t + j + 1 end
if i == j then return t end
for k = 0 , ( j - i + 1 ) / 2 - 1 , math.sign ( j - i ) do
t [ i + k ] , t [ j - k ] = t [ j - k ] , t [ i + k ]
end
return t
end
-- Shifts the table to the right n times, the last value is warped over to become the first value
-- t = {1, 2, 3, 4}
-- table.rotate(t) -> {4, 1, 2, 3}
-- table.rotate(t, 2) -> {3, 4, 1, 2}
function table . rotate ( t , n )
if not n then n = 1 end
if n < 0 then n = # t + n end
t = table.reverse ( t , 1 , # t )
t = table.reverse ( t , 1 , # t - n )
t = table.reverse ( t , # t - n + 1 , # t )
return t
end
-- Returns a random value from the table
-- t = {1, 2, 3}
-- table.random(t) -> 1 or 2 or 3 randomly
function table . random ( t )
return t [ love.math . random ( 1 , # t ) ]
end
-- t = {1, 2, 3, 4, 5}
-- table.shuffle(t) -> {3, 4, 1, 2, 5}
-- table.shuttle(t) -> {2, 5, 1, 4, 3}
-- table.shuffle(t) -> {5, 4, 1, 3, 2}
function table . shuffle ( t )
for i = # t , 2 , - 1 do
local j = love.math . random ( i )
t [ i ] , t [ j ] = t [ j ] , t [ i ]
end
return t
end
-- Merges both tables based on their indexes, if the second table has values in the same indexes as the first table then those will overwrite the first values.
-- t1 = {1, 2, ['a'] = 3, ['b'] = function() end}
-- t2 = {nil, 8, 4, 5, ['a'] = 8}
-- table.merge(t1, t2) -> {1, 2, 8, 4, 5, ['a'] = 8, ['b'] = function() end}
function table . merge ( t1 , t2 )
local out = { }
for k , v in pairs ( t1 ) do out [ k ] = v end
for k , v in pairs ( t2 ) do out [ k ] = v end
return out
end