Module:table: Verskil tussen weergawes
Content deleted Content added
Yurik (Besprekings | bydraes) update manually from mw |
No edit summary |
||
Lyn 1:
--[[
------------------------------------------------------------------------------------
-- table
-- --
-- This module
-- It is a meta-module, meant to be called from other Lua modules, and should --
-- not be called directly from #invoke. --
------------------------------------------------------------------------------------
--]]
--[[
Inserting new values into a table using a local "index" variable, which is
incremented each time, is faster than using "table.insert(t, x)" or
"t[#t + 1] = x". See the talk page.
]]
local libraryUtil = require('libraryUtil')
local
-- Define often-used variables and functions.
Line 18 ⟶ 24:
local checkType = libraryUtil.checkType
local checkTypeMulti = libraryUtil.checkTypeMulti
local function _check(funcName, expectType)
if type(expectType) == "string" then
return function(argIndex, arg, nilOk)
checkType(funcName, argIndex, arg, expectType, nilOk)
end
else
return function(argIndex, arg, expectType, nilOk)
if type(expectType) == "table" then
checkTypeMulti(funcName, argIndex, arg, expectType, nilOk)
else
checkType(funcName, argIndex, arg, expectType, nilOk)
end
end
end
end
--[[
Line 29 ⟶ 51:
------------------------------------------------------------------------------------
--]]
function
end
Line 47 ⟶ 65:
------------------------------------------------------------------------------------
--]]
function
if type(v) == 'number' and tostring(v) == '-nan' then
return true
Line 64 ⟶ 82:
------------------------------------------------------------------------------------
--]]
function
local ret = {}
for k, v in pairs(t) do
Line 70 ⟶ 88:
end
return ret
end
--[[
Shallow copy
]]
function export.shallowcopy(orig)
local orig_type = type(orig)
local copy
if orig_type == 'table' then
copy = {}
for orig_key, orig_value in pairs(orig) do
copy[orig_key] = orig_value
end
else -- number, string, boolean, etc
copy = orig
end
return copy
end
--[[
Recursive deep copy function
Equivalent to mw.clone?
]]
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)
end
end
else -- number, string, boolean, etc
copy = orig
end
return copy
end
function export.deepcopy(orig, noMetatable, already_seen)
checkType("deepcopy", 3, already_seen, "table", true)
return deepcopy(orig, not noMetatable, already_seen)
end
Line 81 ⟶ 155:
------------------------------------------------------------------------------------
--]]
function
checkType('removeDuplicates', 1, t, 'table')
local isNan =
local ret, exists = {}, {}
local index = 1
for _, v in ipairs(t) do
if isNan(v) then
-- NaNs can't be table keys, and they are also unique, so we don't need to check existence.
ret[
index = index + 1
else
if not exists[v] then
ret[
index = index + 1
exists[v] = true
end
end
end
return ret
end
--[[
Line 107 ⟶ 184:
------------------------------------------------------------------------------------
--]]
function
if not checked then
checkType('numKeys', 1, t, 'table')
end
local isPositiveInteger = export.isPositiveInteger
local nums = {}
local index = 1
for k, _ in pairs(t) do
if isPositiveInteger(k) then
nums[
index = index + 1
end
end
table.sort(nums)
return nums
end
function export.maxIndex(t)
checkType('maxIndex', 1, t, 'table')
local positiveIntegerKeys = export.numKeys(t)
if positiveIntegerKeys[1] then
return math.max(unpack(positiveIntegerKeys))
else
return 0 -- ???
end
end
Line 125 ⟶ 216:
--
-- This takes a table and returns an array containing the numbers of keys with the
-- specified prefix and suffix.
-- affixNums({a1 = 'foo', a3 = 'bar', a6 = 'baz'}
-- ↓
-- {1, 3, 6}.
------------------------------------------------------------------------------------
--]]
function
local check = _check('affixNums')
check(1, t, 'table')
check(3, suffix, 'string', true)
local function cleanPattern(s)
-- Cleans a pattern so that the magic characters ()%.[]*+-?^$ are interpreted literally.
Line 140 ⟶ 233:
return s
end
prefix = prefix or ''
suffix = suffix or ''
Line 146 ⟶ 239:
suffix = cleanPattern(suffix)
local pattern = '^' .. prefix .. '([1-9]%d*)' .. suffix .. '$'
local nums = {}
local index = 1
for k, _ in pairs(t) do
if type(k) == 'string' then
local num = mw.ustring.match(k, pattern)
if num then
nums[
index = index + 1
end
end
Line 165 ⟶ 260:
--
-- Given a table with keys like ("foo1", "bar1", "foo2", "baz2"), returns a table
-- of subtables in the format
-- { [1] = {foo = 'text', bar = 'text'}, [2] = {foo = 'text', baz = 'text'} }
-- Keys that don't end with an integer are stored in a subtable named "other".
Line 172 ⟶ 267:
------------------------------------------------------------------------------------
--]]
function
local check = _check('numData')
check(1, t, 'table')
check(2, compress, 'boolean', true)
local ret = {}
for k, v in pairs(t) do
local prefix, num =
if num then
num = tonumber(num)
Line 195 ⟶ 292:
if compress then
local other = ret.other
ret =
ret.other = other
end
Line 210 ⟶ 307:
------------------------------------------------------------------------------------
--]]
function
checkType('compressSparseArray', 1, t, 'table')
local ret = {}
local
local nums = export.numKeys(t)
for _, num in ipairs(nums) do
ret[
index = index + 1
end
return ret
Line 228 ⟶ 327:
------------------------------------------------------------------------------------
--]]
function
checkType('sparseIpairs', 1, t, 'table')
local nums =
local i = 0
return function()
i = i + 1
return key, t[key]
else
Line 252 ⟶ 350:
------------------------------------------------------------------------------------
--]]
function export.size(t)
checkType('size', 1, t, 'table')
local i = 0
for
i = i + 1
end
Line 262 ⟶ 359:
end
--[[
-- This returns the length of a table, or the first integer key n counting from
-- 1 such that t[n + 1] is nil. 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 #.
--]]
function export.length(t)
local i = 0
repeat
i = i + 1
until t[i] == nil
return i - 1
end
--[[
Takes table and a value to be found.
If the value is in the array portion of the table, return true.
If the value is in the hashmap or not in the table, return false.
]]
function export.contains(list, x)
for _, v in ipairs(list) do
if v == x then return true end
end
return false
end
--[[
Recursively compare two values that may be tables, including tables with
nested tables as values. Return true if both values are structurally equal.
Note that this handles arbitary levels of nesting. If all tables are known
to be lists (with only integral keys), use export.deepEqualsList, which will
be more efficient.
NOTE: This is *NOT* smart enough to properly handle cycles; in such a case, it
will get into an infinite loop.
]]
function export.deepEquals(x, y)
if type(x) == "table" and type(y) == "table" then
-- Two tables are the same if they have the same number of elements
-- and all keys that are present in one of the tables compare equal
-- to the corresponding keys in the other table, using structural
-- comparison.
local sizex = 0
for key, value in pairs(x) do
if not export.deepEquals(value, y[key]) then
return false
end
sizex = sizex + 1
end
local sizey = export.size(y)
if sizex ~= sizey then
return false
end
return true
end
return x == y
end
--[[
Recursively compare two values that may be lists (i.e. tables with integral
keys), including lists with nested lists as values. Return true if both values
are structurally equal. Note that this handles arbitary levels of nesting.
Results are undefined if tables with non-integral keys are present anywhere in
either structure; if that may be the case, use export.deepEquals, which will
handle such tables correctly but be less efficient on lists than
export.deepEqualsList.
NOTE: This is *NOT* smart enough to properly handle cycles; in such a case, it
will get into an infinite loop.
]]
function export.deepEqualsList(x, y)
if type(x) == "table" and type(y) == "table" then
if #x ~= #y then
return false
end
for key, value in ipairs(x) do
if not export.deepEqualsList(value, y[key]) then
return false
end
end
return true
end
return x == y
end
--[[
Finds key for specified value in a given table.
Roughly equivalent to reversing the key-value pairs in the table –
reversed_table = { [value1] = key1, [value2] = key2, ... }
– and then returning reversed_table[valueToFind].
The value can only be a string or a number
(not nil, a boolean, a table, or a function).
Only reliable if there is just one key with the specified value.
Otherwise, the function returns the first key found,
and the output is unpredictable.
]]
function export.keyFor(t, valueToFind)
local check = _check('keyFor')
check(1, t, 'table')
check(2, valueToFind, { 'string', 'number' })
for key, value in pairs(t) do
if value == valueToFind then
return key
end
end
return nil
end
--[[
The default sorting function used in export.keysToList if no keySort
is defined.
]]
local function defaultKeySort(key1, key2)
-- "number" < "string", so numbers will be sorted before strings.
local type1, type2 = type(
if type1 ~= type2 then
return type1 < type2
else
return
end
end
--[[
Returns a list of the keys in a table, sorted using either
If there are only numerical keys, numKeys is probably more efficient.
]]
function
if not checked then
local check = _check('keysToList')
check(1, t, 'table')
check(2, keySort, 'function', true)
end
local list = {}
local index = 1
for key,
list[index] = key
index = index + 1
end
-- Place numbers before strings, otherwise sort using <.
if not keySort then
keySort = defaultKeySort
end
table.sort(list, keySort)
return list
Line 303 ⟶ 518:
If there are only numerical keys, sparseIpairs is probably more efficient.
]]
function
local check = _check('keysToList')
check(1, t, 'table')
check(2, keySort, 'function', true)
local list =
local i = 0
Line 321 ⟶ 537:
end
function export.reverseIpairs(list)
checkType('reverse_ipairs', 1, list, 'table')
local i =
return function()
i = i
if
return
else
return nil, nil
end
end
end
--[=[
Joins an array with serial comma and serial conjunction, normally "and".
An improvement on mw.text.listToText, which doesn't properly handle serial
commas.
Options:
- conj
Conjunction to use; defaults to "and".
- italicizeConj
Italicize conjunction: for [[Module:Template:also]]
- dontTag
Don't tag the serial comma and serial "and". For error messages, in
which HTML cannot be used.
]=]
function export.serialCommaJoin(seq, options)
local check = _check("serialCommaJoin", "table")
check(1, seq)
check(2, options, true)
local length = #seq
if not options then
options = {}
end
local conj
if length > 1 then
conj = options.conj or "and"
if options.italicizeConj then
conj = "''" .. conj .. "''"
end
end
if
elseif length == 1 then
return seq[1] -- nothing to join
elseif length == 2 then
return seq[1] .. " " .. conj .. " " .. seq[2]
else
local comma = options.dontTag and "," or '<span class="serial-comma">,</span>'
conj = options.dontTag and ' ' .. conj .. " " or '<span class="serial-and"> ' .. conj .. '</span> '
return table.concat(seq, ", ", 1, length - 1) ..
comma .. conj .. seq[length]
end
end
Line 409 ⟶ 603:
sparseConcat{ nil, b, c, d } => "bcd"
]]
function
local list = {}
local list_i = 0
for _, v in
list_i = list_i + 1
list[list_i] = v
Line 422 ⟶ 616:
--[[
Values of numberic keys in array portion of table are reversed:
{ "a", "b", "c" } -> { "c", "b", "a" }
--]]
function
checkType("reverse", 1, t, "table")
local new_t = {}
local new_t_i = 1
for i = #t, 1, -1 do
new_t[new_t_i] = t[i]
new_t_i = new_t_i + 1
end
return
end
function
return table.concat(export.reverse(t), sep, i, j)
end
-- { "a", "b", "c" } -> { a = 1, b = 2, c = 3 }
function export.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 export.listToSet(t)
checkType("listToSet", 1, t, "table")
local set = {}
for _, item in ipairs(t) do
set[item] = true
end
return set
end
--[[
Returns true if all keys in the table are consecutive integers starting at 1.
--]]
function export.isArray(t)
checkType("isArray", 1, t, "table")
local i = 0
for _ in pairs(t) do
i = i + 1
if t[i] == nil then
return false
end
end
return true
end
return
|