در حال ویرایش پودمان:TableTools
این ویرایش را میتوان خنثی کرد. لطفاً تفاوت زیر را بررسی کنید تا تأیید کنید که این چیزی است که میخواهید انجام دهید، سپس تغییرات زیر را ذخیره کنید تا خنثیسازی ویرایش را به پایان ببرید.
نسخهٔ فعلی | متن شما | ||
خط ۱: | خط ۱: | ||
--[[ | |||
------------------------------------------------------------------------------------ | ------------------------------------------------------------------------------------ | ||
-- | -- TableTools -- | ||
-- -- | -- -- | ||
-- This module includes a number of functions for dealing with Lua tables. -- | -- 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 | -- It is a meta-module, meant to be called from other Lua modules, and should -- | ||
-- be called directly from #invoke. | -- not be called directly from #invoke. -- | ||
------------------------------------------------------------------------------------ | ------------------------------------------------------------------------------------ | ||
--]] | |||
local libraryUtil = require('libraryUtil') | local libraryUtil = require('libraryUtil') | ||
خط ۱۷: | خط ۱۹: | ||
local checkTypeMulti = libraryUtil.checkTypeMulti | local checkTypeMulti = libraryUtil.checkTypeMulti | ||
--[[ | |||
------------------------------------------------------------------------------------ | ------------------------------------------------------------------------------------ | ||
-- isPositiveInteger | -- isPositiveInteger | ||
خط ۲۵: | خط ۲۸: | ||
-- hash part of a table. | -- hash part of a table. | ||
------------------------------------------------------------------------------------ | ------------------------------------------------------------------------------------ | ||
--]] | |||
function p.isPositiveInteger(v) | function p.isPositiveInteger(v) | ||
return type(v) == 'number' and v >= 1 and floor(v) == v and v < infinity | return type(v) == 'number' and v >= 1 and floor(v) == v and v < infinity | ||
end | end | ||
--[[ | |||
------------------------------------------------------------------------------------ | ------------------------------------------------------------------------------------ | ||
-- isNan | -- isNan | ||
-- | -- | ||
-- This function returns true if the given number is a NaN value, and false | -- This function returns true if the given number is a NaN value, and false | ||
-- not. Although it doesn't operate on tables, it is included here as it is | -- if not. Although it doesn't operate on tables, it is included here as it is | ||
-- for determining whether a value can be a valid table key. Lua will | -- useful for determining whether a value can be a valid table key. Lua will | ||
-- error if a NaN is used as a table key. | -- generate an error if a NaN is used as a table key. | ||
------------------------------------------------------------------------------------ | ------------------------------------------------------------------------------------ | ||
--]] | |||
function p.isNan(v) | function p.isNan(v) | ||
return type(v) == 'number' and v | return type(v) == 'number' and tostring(v) == '-nan' | ||
end | end | ||
--[[ | |||
------------------------------------------------------------------------------------ | ------------------------------------------------------------------------------------ | ||
-- shallowClone | -- shallowClone | ||
خط ۴۸: | خط ۵۵: | ||
-- table will have no metatable of its own. | -- table will have no metatable of its own. | ||
------------------------------------------------------------------------------------ | ------------------------------------------------------------------------------------ | ||
--]] | |||
function p.shallowClone(t) | function p.shallowClone(t) | ||
local ret = {} | local ret = {} | ||
for k, v in pairs(t) do | for k, v in pairs(t) do | ||
خط ۵۷: | خط ۶۴: | ||
end | end | ||
--[[ | |||
------------------------------------------------------------------------------------ | ------------------------------------------------------------------------------------ | ||
-- removeDuplicates | -- removeDuplicates | ||
خط ۶۴: | خط ۷۲: | ||
-- removed, but otherwise the array order is unchanged. | -- removed, but otherwise the array order is unchanged. | ||
------------------------------------------------------------------------------------ | ------------------------------------------------------------------------------------ | ||
function p.removeDuplicates( | --]] | ||
checkType('removeDuplicates', 1, | function p.removeDuplicates(t) | ||
checkType('removeDuplicates', 1, t, 'table') | |||
local isNan = p.isNan | local isNan = p.isNan | ||
local ret, exists = {}, {} | local ret, exists = {}, {} | ||
for | for i, v in ipairs(t) do | ||
if isNan(v) then | if isNan(v) then | ||
-- NaNs can't be table keys, and they are also unique, so we don't need to check existence. | -- NaNs can't be table keys, and they are also unique, so we don't need to check existence. | ||
خط ۷۷: | خط ۸۶: | ||
exists[v] = true | exists[v] = true | ||
end | end | ||
end | end | ||
end | end | ||
return ret | return ret | ||
end | end | ||
--[[ | |||
------------------------------------------------------------------------------------ | ------------------------------------------------------------------------------------ | ||
-- numKeys | -- numKeys | ||
خط ۸۸: | خط ۹۸: | ||
-- keys that have non-nil values, sorted in numerical order. | -- keys that have non-nil values, sorted in numerical order. | ||
------------------------------------------------------------------------------------ | ------------------------------------------------------------------------------------ | ||
--]] | |||
function p.numKeys(t) | function p.numKeys(t) | ||
checkType('numKeys', 1, t, 'table') | checkType('numKeys', 1, t, 'table') | ||
local isPositiveInteger = p.isPositiveInteger | local isPositiveInteger = p.isPositiveInteger | ||
local nums = {} | local nums = {} | ||
for k in pairs(t) do | for k, v in pairs(t) do | ||
if isPositiveInteger(k) then | if isPositiveInteger(k) then | ||
nums[#nums + 1] = k | nums[#nums + 1] = k | ||
خط ۱۰۱: | خط ۱۱۲: | ||
end | end | ||
--[[ | |||
------------------------------------------------------------------------------------ | ------------------------------------------------------------------------------------ | ||
-- affixNums | -- affixNums | ||
خط ۱۰۶: | خط ۱۱۸: | ||
-- This takes a table and returns an array containing the numbers of keys with the | -- This takes a table and returns an array containing the numbers of keys with the | ||
-- specified prefix and suffix. For example, for the table | -- specified prefix and suffix. For example, for the table | ||
-- {a1 = 'foo', a3 = 'bar', a6 = 'baz'} and the prefix "a", affixNums will | -- {a1 = 'foo', a3 = 'bar', a6 = 'baz'} and the prefix "a", affixNums will | ||
-- {1, 3, 6}. | -- return {1, 3, 6}. | ||
------------------------------------------------------------------------------------ | ------------------------------------------------------------------------------------ | ||
--]] | |||
function p.affixNums(t, prefix, suffix) | function p.affixNums(t, prefix, suffix) | ||
checkType('affixNums', 1, t, 'table') | checkType('affixNums', 1, t, 'table') | ||
خط ۱۱۶: | خط ۱۲۹: | ||
local function cleanPattern(s) | local function cleanPattern(s) | ||
-- Cleans a pattern so that the magic characters ()%.[]*+-?^$ are interpreted literally. | -- Cleans a pattern so that the magic characters ()%.[]*+-?^$ are interpreted literally. | ||
s = s:gsub('([%(%)%%%.%[%]%*%+%-%?%^%$])', '%%%1') | |||
return s | |||
end | end | ||
خط ۱۲۶: | خط ۱۴۰: | ||
local nums = {} | local nums = {} | ||
for k in pairs(t) do | for k, v in pairs(t) do | ||
if type(k) == 'string' then | if type(k) == 'string' then | ||
local num = mw.ustring.match(k, pattern) | local num = mw.ustring.match(k, pattern) | ||
if num then | if num then | ||
خط ۱۳۸: | خط ۱۵۲: | ||
end | end | ||
--[[ | |||
------------------------------------------------------------------------------------ | ------------------------------------------------------------------------------------ | ||
-- numData | -- numData | ||
-- | -- | ||
-- Given a table with keys like | -- Given a table with keys like ("foo1", "bar1", "foo2", "baz2"), returns a table | ||
-- of subtables in the format | -- of subtables in the format | ||
-- {[1] = {foo = 'text', bar = 'text'}, [2] = {foo = 'text', baz = 'text'}} | -- { [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". | -- Keys that don't end with an integer are stored in a subtable named "other". | ||
-- compress option compresses the table so that it can be iterated over with | -- The compress option compresses the table so that it can be iterated over with | ||
-- ipairs. | -- ipairs. | ||
------------------------------------------------------------------------------------ | ------------------------------------------------------------------------------------ | ||
--]] | |||
function p.numData(t, compress) | function p.numData(t, compress) | ||
checkType('numData', 1, t, 'table') | checkType('numData', 1, t, 'table') | ||
خط ۱۷۷: | خط ۱۹۳: | ||
end | end | ||
--[[ | |||
------------------------------------------------------------------------------------ | ------------------------------------------------------------------------------------ | ||
-- compressSparseArray | -- compressSparseArray | ||
خط ۱۸۴: | خط ۲۰۱: | ||
-- ipairs. | -- ipairs. | ||
------------------------------------------------------------------------------------ | ------------------------------------------------------------------------------------ | ||
--]] | |||
function p.compressSparseArray(t) | function p.compressSparseArray(t) | ||
checkType('compressSparseArray', 1, t, 'table') | checkType('compressSparseArray', 1, t, 'table') | ||
خط ۱۹۴: | خط ۲۱۲: | ||
end | end | ||
--[[ | |||
------------------------------------------------------------------------------------ | ------------------------------------------------------------------------------------ | ||
-- sparseIpairs | -- sparseIpairs | ||
خط ۲۰۰: | خط ۲۱۹: | ||
-- handle nil values. | -- handle nil values. | ||
------------------------------------------------------------------------------------ | ------------------------------------------------------------------------------------ | ||
--]] | |||
function p.sparseIpairs(t) | function p.sparseIpairs(t) | ||
checkType('sparseIpairs', 1, t, 'table') | checkType('sparseIpairs', 1, t, 'table') | ||
خط ۲۱۶: | خط ۲۳۶: | ||
end | end | ||
--[[ | |||
------------------------------------------------------------------------------------ | ------------------------------------------------------------------------------------ | ||
-- size | -- size | ||
خط ۲۲۲: | خط ۲۴۳: | ||
-- but for arrays it is more efficient to use the # operator. | -- but for arrays it is more efficient to use the # operator. | ||
------------------------------------------------------------------------------------ | ------------------------------------------------------------------------------------ | ||
--]] | |||
function p.size(t) | function p.size(t) | ||
checkType('size', 1, t, 'table') | checkType('size', 1, t, 'table') | ||
local i = 0 | local i = 0 | ||
for | for k in pairs(t) do | ||
i = i + 1 | i = i + 1 | ||
end | end | ||
return i | return i | ||
end | end | ||
local function defaultKeySort(item1, item2) | local function defaultKeySort(item1, item2) | ||
خط ۲۳۶: | خط ۲۶۰: | ||
if type1 ~= type2 then | if type1 ~= type2 then | ||
return type1 < type2 | return type1 < type2 | ||
else -- This will fail with table, boolean, function. | |||
return item1 < item2 | return item1 < item2 | ||
end | end | ||
end | end | ||
-- | --[[ | ||
Returns a list of the keys in a table, sorted using either a default | |||
comparison function or a custom keySort function. | |||
]] | |||
function p.keysToList(t, keySort, checked) | function p.keysToList(t, keySort, checked) | ||
if not checked then | if not checked then | ||
checkType('keysToList', 1, t, 'table') | checkType('keysToList', 1, t, 'table') | ||
checkTypeMulti('keysToList', 2, keySort, {'function', 'boolean', 'nil'}) | checkTypeMulti('keysToList', 2, keySort, { 'function', 'boolean', 'nil' }) | ||
end | end | ||
local | local list = {} | ||
local index = 1 | local index = 1 | ||
for | for key, value in pairs(t) do | ||
list[index] = key | |||
index = index + 1 | index = index + 1 | ||
end | end | ||
if keySort ~= false then | if keySort ~= false then | ||
keySort = type(keySort) == 'function' and keySort or defaultKeySort | keySort = type(keySort) == 'function' and keySort or defaultKeySort | ||
table.sort( | |||
table.sort(list, keySort) | |||
end | end | ||
return | return list | ||
end | end | ||
-- | --[[ | ||
Iterates through a table, with the keys sorted using the keysToList function. | |||
If there are only numerical keys, sparseIpairs is probably more efficient. | |||
]] | |||
function p.sortedPairs(t, keySort) | function p.sortedPairs(t, keySort) | ||
checkType('sortedPairs', 1, t, 'table') | checkType('sortedPairs', 1, t, 'table') | ||
checkType('sortedPairs', 2, keySort, 'function', true) | checkType('sortedPairs', 2, keySort, 'function', true) | ||
local | local list = p.keysToList(t, keySort, true) | ||
local i = 0 | local i = 0 | ||
return function () | return function() | ||
i = i + 1 | i = i + 1 | ||
local key = | local key = list[i] | ||
if key ~= nil then | if key ~= nil then | ||
return key, t[key] | return key, t[key] | ||
خط ۲۹۳: | خط ۳۱۳: | ||
end | end | ||
-- | --[[ | ||
Returns true if all keys in the table are consecutive integers starting at 1. | |||
--]] | |||
function p.isArray(t) | |||
checkType("isArray", 1, t, "table") | |||
-- | |||
function p.isArray( | |||
local i = 0 | local i = 0 | ||
for | for k, v in pairs(t) do | ||
i = i + 1 | i = i + 1 | ||
if | if t[i] == nil then | ||
return false | return false | ||
end | end | ||
خط ۳۱۳: | خط ۳۲۹: | ||
end | end | ||
-- | -- { "a", "b", "c" } -> { a = 1, b = 2, c = 3 } | ||
function p.invert(array) | |||
checkType("invert", 1, array, "table") | |||
function p.invert( | |||
checkType("invert", 1, | |||
local map = {} | local map = {} | ||
for i, v in ipairs( | for i, v in ipairs(array) do | ||
map[v] = i | |||
end | end | ||
return map | return map | ||
end | end | ||
-- | --[[ | ||
{ "a", "b", "c" } -> { ["a"] = true, ["b"] = true, ["c"] = true } | |||
--]] | |||
function p.listToSet(t) | |||
checkType("listToSet", 1, t, "table") | |||
-- | |||
function p.listToSet( | |||
checkType("listToSet", 1, | |||
local set = {} | local set = {} | ||
for _, | for _, item in ipairs(t) do | ||
set[item] = true | |||
end | end | ||
return set | return set | ||
end | end | ||
-- | --[[ | ||
Recursive deep copy function. | |||
Preserves identities of subtables. | |||
]] | |||
local function _deepCopy(orig, includeMetatable, already_seen) | local function _deepCopy(orig, includeMetatable, already_seen) | ||
-- Stores copies of tables indexed by the original table. | -- Stores copies of tables indexed by the original table. | ||
already_seen = already_seen or {} | already_seen = already_seen or {} | ||
local copy = already_seen[orig] | local copy = already_seen[orig] | ||
if copy ~= nil then | if copy ~= nil then | ||
return copy | return copy | ||
end | end | ||
if type(orig) == 'table' then | if type(orig) == 'table' then | ||
copy = {} | copy = {} | ||
for orig_key, orig_value in pairs(orig) do | for orig_key, orig_value in pairs(orig) do | ||
copy[ | copy[deepcopy(orig_key, includeMetatable, already_seen)] = deepcopy(orig_value, includeMetatable, already_seen) | ||
end | end | ||
already_seen[orig] = copy | already_seen[orig] = copy | ||
if includeMetatable then | if includeMetatable then | ||
local mt = getmetatable(orig) | local mt = getmetatable(orig) | ||
if mt ~= nil then | if mt ~= nil then | ||
local mt_copy = | local mt_copy = deepcopy(mt, includeMetatable, already_seen) | ||
setmetatable(copy, mt_copy) | setmetatable(copy, mt_copy) | ||
already_seen[mt] = mt_copy | already_seen[mt] = mt_copy | ||
خط ۴۱۱: | خط ۳۹۲: | ||
function p.deepCopy(orig, noMetatable, already_seen) | function p.deepCopy(orig, noMetatable, already_seen) | ||
checkType("deepCopy", 3, already_seen, "table", true) | checkType("deepCopy", 3, already_seen, "table", true) | ||
return _deepCopy(orig, not noMetatable, already_seen) | return _deepCopy(orig, not noMetatable, already_seen) | ||
end | 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) | function p.sparseConcat(t, sep, i, j) | ||
local | local list = {} | ||
local | local list_i = 0 | ||
for _, v in p.sparseIpairs(t) do | for _, v in p.sparseIpairs(t) do | ||
list_i = list_i + 1 | |||
list[list_i] = v | |||
end | 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) | function p.length(t, prefix) | ||
-- requiring module inline so that [[Module: | -- requiring module inline so that [[Module:Exponental search]] | ||
-- only needed by this one function doesn't get millions of transclusions | -- which is only needed by this one function | ||
-- doesn't get millions of transclusions | |||
local expSearch = require("Module:Exponential search") | local expSearch = require("Module:Exponential search") | ||
checkType('length', 1, t, 'table') | checkType('length', 1, t, 'table') | ||
checkType('length', 2, prefix, 'string', true) | checkType('length', 2, prefix, 'string', true) | ||
return expSearch(function (i) | return expSearch(function(i) | ||
local key | local key | ||
if prefix then | if prefix then | ||
خط ۴۶۰: | خط ۴۴۱: | ||
end) or 0 | end) or 0 | ||
end | end | ||
function p.inArray(arr, valueToFind) | function p.inArray(arr, valueToFind) | ||
checkType("inArray", 1, arr, "table") | checkType("inArray", 1, arr, "table") | ||
-- if valueToFind is nil, error? | -- if valueToFind is nil, error? | ||
for _, v in ipairs(arr) do | for _, v in ipairs(arr) do | ||
if v == valueToFind then | if v == valueToFind then | ||
خط ۴۷۵: | خط ۴۵۱: | ||
end | end | ||
end | end | ||
return false | return false | ||
end | end | ||
return p | return p |