Mô đun:TableTools

--
------------------------------------------------------------------------------------
-- TableTools --
-- --
-- This module includes a number of functions for dealing with Lua tables. --
-- It is a meta-module, meant to be called from other Lua modules, and should --
-- not be called directly from invoke. --
------------------------------------------------------------------------------------
--

local libraryUtil = require('libraryUtil')

local p = {}

-- Define often-used variables and functions.
local floor = math.floor
local infinity = math.huge
local checkType = libraryUtil.checkType
local checkTypeMulti = libraryUtil.checkTypeMulti

--
------------------------------------------------------------------------------------
-- isPositiveInteger
--
-- This function returns true if the given value is a positive integer, and false
-- if not. Although it doesn't operate on tables, it is included here as it is
-- useful for determining whether a given table key is in the array part or the
-- hash part of a table.
------------------------------------------------------------------------------------
--
function p.isPositiveInteger(v)
return type(v) == 'number' and v >= 1 and floor(v) == v and v { a = 1, b = 2, c = 3 }
function p.invert(array)
checkType("invert", 1, array, "table")

local map = {}
for i, v in ipairs(array) do
map[v] = i
end

return map
end

--[[
{ "a", "b", "c" } -> { ["a"] = true, ["b"] = true, ["c"] = true }
--]]
function p.listToSet(t)
checkType("listToSet", 1, t, "table")

local set = {}
for _, item in ipairs(t) do
set[item] = true
end

return set
end

--
Recursive deep copy function.
Preserves identities of subtables.


local function _deepCopy(orig, includeMetatable, already_seen)
-- Stores copies of tables indexed by the original table.
already_seen = already_seen or {}

local copy = already_seen[orig]
if copy ~= nil then
return copy
end

if type(orig) == 'table' then
copy = {}
for orig_key, orig_value in pairs(orig) do
copy[deepcopy(orig_key, includeMetatable, already_seen)] = deepcopy(orig_value, includeMetatable, already_seen)
end
already_seen[orig] = copy

if includeMetatable then
local mt = getmetatable(orig)
if mt ~= nil then
local mt_copy = deepcopy(mt, includeMetatable, already_seen)
setmetatable(copy, mt_copy)
already_seen[mt] = mt_copy
end
end
else -- number, string, boolean, etc
copy = orig
end
return copy
end

function p.deepCopy(orig, noMetatable, already_seen)
checkType("deepCopy", 3, already_seen, "table", true)

return _deepCopy(orig, not noMetatable, already_seen)
end

--
Concatenates all values in the table that are indexed by a number, in order.
sparseConcat{ a, nil, c, d } => "acd"
sparseConcat{ nil, b, c, d } => "bcd"

function p.sparseConcat(t, sep, i, j)
local list = {}

local list_i = 0
for _, v in p.sparseIpairs(t) do
list_i = list_i + 1
list[list_i] = v
end

return table.concat(list, sep, i, j)
end

--
-- Finds the length of an array, or of a quasi-array with keys such
-- as "data1", "data2", etc., using an exponental search algorithm.
-- It is similar to the operator , but may return
-- a different value when there are gaps in the array portion of the table.
-- Intended to be used on data loaded with mw.loadData. For other tables, use .
-- Note: frame.args in frame object always be set to 0, regardless of
-- the number of unnamed template parameters, so use this function for
-- frame.args.
--

function p.length(t, prefix)
-- requiring module inline so that Module:Exponental search
-- which is only needed by this one function
-- doesn't get millions of transclusions
local expSearch = require("Mô đun:Exponential search")
checkType('length', 1, t, 'table')
checkType('length', 2, prefix, 'string', true)
return expSearch(function(i)
local key
if prefix then
key = prefix .. tostring(i)
else
key = i
end
return t[key] ~= nil
end) or 0
end
function p.inArray(arr, valueToFind)
checkType("inArray", 1, arr, "table")

-- if valueToFind is nil, error?

for _, v in ipairs(arr) do
if v == valueToFind then
return true
end
end

return false
end

return p