-- 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} -- If n is defined then it always returns a table, even with only 1 value. function table.head(t, n) local out = {} for i = 1, (n or 1) do table.push(out, t[i]) end if n then return out else if #out == 1 then return out[1] else return out end end end -- Returns the last n values -- t = {5, 4, 3, 2, 1} -- table.tail(t) -> 1 -- table.tail(t, 2) -> {2, 1} -- If n is defined then it always returns a table, even with only 1 value. function table.tail(t, n) local out = {} for i = #t-(n or #t-1)+1, #t do table.push(out, t[i]) end if n then return out else if #out == 1 then return out[1] else return out end 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, ...) local memo = dv or t[1] if dv then for i = 1, #t do memo = f(memo, t[i], i, ...) end else for i = 2, #t do memo = f(memo, t[i], i, ...) end 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 pairs(t) do if type(k) ~= "number" then k = '"' .. k .. '"' end str = str .. "[" .. k .. "] = " .. table.tostring(v) .. ", " end if str ~= "{" then return str:sub(1, -3) .. "}" else return str .. "}" end elseif type(t) == "string" then return '"' .. tostring(t) .. '"' 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 function table.first2(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 return out 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