-- {a = 1, b = 2, c = 3}. Duplicates are not supported (result values refer to
-- the index of the last duplicate) and NaN values are ignored.
---
function p.invert(arr)
checkType("invert", 1, arr, "table")
local isNan = p.isNan
local map = {}
for i, v in ipairs(arr) do
if not isNan(v) then
map[v] = i
end
end  
return map
end  
---
-- listToSet
---
-- Creates a set from the array part of the table. Indexing the set by any of the
-- values of the array returns true. For example, {"a", "b", "c"} ->
-- {a = true, b = true, c = true}. NaN values are ignored as Lua considers them
-- never equal to any value (including other NaNs or even themselves).
---
function p.listToSet(arr)
checkType("listToSet", 1, arr, "table")
local isNan = p.isNan
local set = {}
for _, v in ipairs(arr) do
if not isNan(v) then
set[v] = true
end
end  
return set
end  
---
-- deepCopy
---
-- Recursive deep copy function. Preserves identities of subtables.
---
local function _deepCopy(orig, includeMetatable, already_seen)
if type(orig) ~= "table" then
return orig
end  
-- already_seen stores copies of tables indexed by the original table.
local copy = already_seen[orig]
if copy ~= nil then
return copy
end  
copy = {}
already_seen[orig] = copy -- memoize before any recursion, to avoid infinite loops  
for orig_key, orig_value in pairs(orig) do
copy[_deepCopy(orig_key, includeMetatable, already_seen)] = _deepCopy(orig_value, includeMetatable, already_seen)
end  
if includeMetatable then
local mt = getmetatable(orig)
if mt ~= nil then
setmetatable(copy, _deepCopy(mt, true, already_seen))
end
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 or {})
end  
---
-- sparseConcat
---
-- 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 arr = {}  
local arr_i = 0
for _, v in p.sparseIpairs(t) do
arr_i = arr_i + 1
arr[arr_i] = v
end  
return table.concat(arr, sep, i, j)
end  
---
-- length
---
-- Finds the length of an array, or of a quasi-array with keys such as "data1",
-- "data2", etc., using an exponential 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: #.args in object always be set to 0, regardless of the number
-- of unnamed template parameters, so use this function for .args.
---
function p.length(t, prefix)
-- requiring module inline so that Module:Exponential search which is
-- only needed by this one function doesn't get millions of transclusions
local expSearch = require("Module: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  
---
-- inArray
---
-- Returns true if searchElement is a member of the array, and false otherwise.
-- Equivalent to JavaScript array.includes(searchElement) or
-- array.includes(searchElement, fromIndex), except fromIndex is 1 indexed
---
function p.inArray(array, searchElement, fromIndex)
checkType("inArray", 1, array, "table")
-- if searchElement is nil, error?  
fromIndex = tonumber(fromIndex)
if fromIndex then
if (fromIndex < 0) then
fromIndex = #array + fromIndex + 1
end
if fromIndex < 1 then fromIndex = 1 end
for _, v in ipairs({unpack(array, fromIndex)}) do
if v == searchElement then
return true
end
end
else
for _, v in pairs(array) do
if v == searchElement then
return true
end
end
end
return false
end  
---
-- merge
---
-- Given the arrays, returns an array containing the elements of each input array
-- in sequence.
---
function p.merge(...)
local arrays = {...}
local ret = {}
for i, arr in ipairs(arrays) do
checkType('merge', i, arr, 'table')
for _, v in ipairs(arr) do
ret[#ret + 1] = v
end
end
return ret
end  
---
-- extend
---
-- Extends the first array in place by appending all elements from the second
-- array.
---
function p.extend(arr1, arr2)
checkType('extend', 1, arr1, 'table')
checkType('extend', 2, arr2, 'table')  
for _, v in ipairs(arr2) do
arr1[#arr1 + 1] = v
end
end  
return p