https://sarkarverse.org/index.php?title=Module:TableTools&feed=atom&action=historyModule:TableTools - Revision history2024-03-29T10:19:38ZRevision history for this page on the wikiMediaWiki 1.39.0https://sarkarverse.org/index.php?title=Module:TableTools&diff=25161&oldid=prevT12: 1 revision2014-05-27T10:25:20Z<p>1 revision</p>
<p><b>New page</b></p><div>--[[<br />
------------------------------------------------------------------------------------<br />
-- TableTools --<br />
-- --<br />
-- This module includes a number of functions for dealing with Lua tables. --<br />
-- It is a meta-module, meant to be called from other Lua modules, and should --<br />
-- not be called directly from #invoke. --<br />
------------------------------------------------------------------------------------<br />
--]]<br />
<br />
local libraryUtil = require('libraryUtil')<br />
<br />
local p = {}<br />
<br />
-- Define often-used variables and functions.<br />
local floor = math.floor<br />
local infinity = math.huge<br />
local checkType = libraryUtil.checkType<br />
<br />
--[[<br />
------------------------------------------------------------------------------------<br />
-- isPositiveInteger<br />
--<br />
-- This function returns true if the given value is a positive integer, and false<br />
-- if not. Although it doesn't operate on tables, it is included here as it is<br />
-- useful for determining whether a given table key is in the array part or the<br />
-- hash part of a table.<br />
------------------------------------------------------------------------------------<br />
--]]<br />
function p.isPositiveInteger(v)<br />
if type(v) == 'number' and v >= 1 and floor(v) == v and v < infinity then<br />
return true<br />
else<br />
return false<br />
end<br />
end<br />
<br />
--[[<br />
------------------------------------------------------------------------------------<br />
-- isNan<br />
--<br />
-- This function returns true if the given number is a NaN value, and false<br />
-- if not. Although it doesn't operate on tables, it is included here as it is<br />
-- useful for determining whether a value can be a valid table key. Lua will<br />
-- generate an error if a NaN is used as a table key.<br />
------------------------------------------------------------------------------------<br />
--]]<br />
function p.isNan(v)<br />
if type(v) == 'number' and tostring(v) == '-nan' then<br />
return true<br />
else<br />
return false<br />
end<br />
end<br />
<br />
--[[<br />
------------------------------------------------------------------------------------<br />
-- shallowClone<br />
--<br />
-- This returns a clone of a table. The value returned is a new table, but all<br />
-- subtables and functions are shared. Metamethods are respected, but the returned<br />
-- table will have no metatable of its own.<br />
------------------------------------------------------------------------------------<br />
--]]<br />
function p.shallowClone(t)<br />
local ret = {}<br />
for k, v in pairs(t) do<br />
ret[k] = v<br />
end<br />
return ret<br />
end<br />
<br />
--[[<br />
------------------------------------------------------------------------------------<br />
-- removeDuplicates<br />
--<br />
-- This removes duplicate values from an array. Non-positive-integer keys are<br />
-- ignored. The earliest value is kept, and all subsequent duplicate values are<br />
-- removed, but otherwise the array order is unchanged.<br />
------------------------------------------------------------------------------------<br />
--]]<br />
function p.removeDuplicates(t)<br />
checkType('removeDuplicates', 1, t, 'table')<br />
local isNan = p.isNan<br />
local ret, exists = {}, {}<br />
for i, v in ipairs(t) do<br />
if isNan(v) then<br />
-- NaNs can't be table keys, and they are also unique, so we don't need to check existence.<br />
ret[#ret + 1] = v<br />
else<br />
if not exists[v] then<br />
ret[#ret + 1] = v<br />
exists[v] = true<br />
end<br />
end <br />
end<br />
return ret<br />
end <br />
<br />
--[[<br />
------------------------------------------------------------------------------------<br />
-- numKeys<br />
--<br />
-- This takes a table and returns an array containing the numbers of any numerical<br />
-- keys that have non-nil values, sorted in numerical order.<br />
------------------------------------------------------------------------------------<br />
--]]<br />
function p.numKeys(t)<br />
checkType('numKeys', 1, t, 'table')<br />
local isPositiveInteger = p.isPositiveInteger<br />
local nums = {}<br />
for k, v in pairs(t) do<br />
if isPositiveInteger(k) then<br />
nums[#nums + 1] = k<br />
end<br />
end<br />
table.sort(nums)<br />
return nums<br />
end<br />
<br />
--[[<br />
------------------------------------------------------------------------------------<br />
-- affixNums<br />
--<br />
-- This takes a table and returns an array containing the numbers of keys with the<br />
-- specified prefix and suffix. For example, for the table<br />
-- {a1 = 'foo', a3 = 'bar', a6 = 'baz'} and the prefix "a", affixNums will<br />
-- return {1, 3, 6}.<br />
------------------------------------------------------------------------------------<br />
--]]<br />
function p.affixNums(t, prefix, suffix)<br />
checkType('affixNums', 1, t, 'table')<br />
checkType('affixNums', 2, prefix, 'string', true)<br />
checkType('affixNums', 3, suffix, 'string', true)<br />
<br />
local function cleanPattern(s)<br />
-- Cleans a pattern so that the magic characters ()%.[]*+-?^$ are interpreted literally.<br />
s = s:gsub('([%(%)%%%.%[%]%*%+%-%?%^%$])', '%%%1')<br />
return s<br />
end<br />
<br />
prefix = prefix or ''<br />
suffix = suffix or ''<br />
prefix = cleanPattern(prefix)<br />
suffix = cleanPattern(suffix)<br />
local pattern = '^' .. prefix .. '([1-9]%d*)' .. suffix .. '$'<br />
<br />
local nums = {}<br />
for k, v in pairs(t) do<br />
if type(k) == 'string' then <br />
local num = mw.ustring.match(k, pattern)<br />
if num then<br />
nums[#nums + 1] = tonumber(num)<br />
end<br />
end<br />
end<br />
table.sort(nums)<br />
return nums<br />
end<br />
<br />
--[[<br />
------------------------------------------------------------------------------------<br />
-- numData<br />
--<br />
-- Given a table with keys like ("foo1", "bar1", "foo2", "baz2"), returns a table<br />
-- of subtables in the format <br />
-- { [1] = {foo = 'text', bar = 'text'}, [2] = {foo = 'text', baz = 'text'} }<br />
-- Keys that don't end with an integer are stored in a subtable named "other".<br />
-- The compress option compresses the table so that it can be iterated over with<br />
-- ipairs.<br />
------------------------------------------------------------------------------------<br />
--]]<br />
function p.numData(t, compress)<br />
checkType('numData', 1, t, 'table')<br />
checkType('numData', 2, compress, 'boolean', true)<br />
local ret = {}<br />
for k, v in pairs(t) do<br />
local prefix, num = mw.ustring.match(tostring(k), '^([^0-9]*)([1-9][0-9]*)$')<br />
if num then<br />
num = tonumber(num)<br />
local subtable = ret[num] or {}<br />
if prefix == '' then<br />
-- Positional parameters match the blank string; put them at the start of the subtable instead.<br />
prefix = 1<br />
end<br />
subtable[prefix] = v<br />
ret[num] = subtable<br />
else<br />
local subtable = ret.other or {}<br />
subtable[k] = v<br />
ret.other = subtable<br />
end<br />
end<br />
if compress then<br />
local other = ret.other<br />
ret = p.compressSparseArray(ret)<br />
ret.other = other<br />
end<br />
return ret<br />
end<br />
<br />
--[[<br />
------------------------------------------------------------------------------------<br />
-- compressSparseArray<br />
--<br />
-- This takes an array with one or more nil values, and removes the nil values<br />
-- while preserving the order, so that the array can be safely traversed with<br />
-- ipairs.<br />
------------------------------------------------------------------------------------<br />
--]]<br />
function p.compressSparseArray(t)<br />
checkType('compressSparseArray', 1, t, 'table')<br />
local ret = {}<br />
local nums = p.numKeys(t)<br />
for _, num in ipairs(nums) do<br />
ret[#ret + 1] = t[num]<br />
end<br />
return ret<br />
end<br />
<br />
--[[<br />
------------------------------------------------------------------------------------<br />
-- sparseIpairs<br />
--<br />
-- This is an iterator for sparse arrays. It can be used like ipairs, but can<br />
-- handle nil values.<br />
------------------------------------------------------------------------------------<br />
--]]<br />
function p.sparseIpairs(t)<br />
checkType('sparseIpairs', 1, t, 'table')<br />
local nums = p.numKeys(t)<br />
local i = 0<br />
local lim = #nums<br />
return function ()<br />
i = i + 1<br />
if i <= lim then<br />
local key = nums[i]<br />
return key, t[key]<br />
else<br />
return nil, nil<br />
end<br />
end<br />
end<br />
<br />
--[[<br />
------------------------------------------------------------------------------------<br />
-- size<br />
--<br />
-- This returns the size of a key/value pair table. It will also work on arrays,<br />
-- but for arrays it is more efficient to use the # operator.<br />
------------------------------------------------------------------------------------<br />
--]]<br />
function p.size(t)<br />
checkType('size', 1, t, 'table')<br />
local i = 0<br />
for k in pairs(t) do<br />
i = i + 1<br />
end<br />
return i<br />
end<br />
<br />
return p</div>T12https://sarkarverse.org/index.php?title=Module:TableTools&diff=16283&oldid=prevT12: 1 revision2013-12-29T12:38:26Z<p>1 revision</p>
<p><b>New page</b></p><div>--[[<br />
------------------------------------------------------------------------------------<br />
-- TableTools --<br />
-- --<br />
-- This module includes a number of functions for dealing with Lua tables. --<br />
-- It is a meta-module, meant to be called from other Lua modules, and should --<br />
-- not be called directly from #invoke. --<br />
------------------------------------------------------------------------------------<br />
--]]<br />
<br />
local libraryUtil = require('libraryUtil')<br />
<br />
local p = {}<br />
<br />
-- Define often-used variables and functions.<br />
local floor = math.floor<br />
local infinity = math.huge<br />
local checkType = libraryUtil.checkType<br />
<br />
--[[<br />
------------------------------------------------------------------------------------<br />
-- isPositiveInteger<br />
--<br />
-- This function returns true if the given value is a positive integer, and false<br />
-- if not. Although it doesn't operate on tables, it is included here as it is<br />
-- useful for determining whether a given table key is in the array part or the<br />
-- hash part of a table.<br />
------------------------------------------------------------------------------------<br />
--]]<br />
function p.isPositiveInteger(v)<br />
if type(v) == 'number' and v >= 1 and floor(v) == v and v < infinity then<br />
return true<br />
else<br />
return false<br />
end<br />
end<br />
<br />
--[[<br />
------------------------------------------------------------------------------------<br />
-- isNan<br />
--<br />
-- This function returns true if the given number is a NaN value, and false<br />
-- if not. Although it doesn't operate on tables, it is included here as it is<br />
-- useful for determining whether a value can be a valid table key. Lua will<br />
-- generate an error if a NaN is used as a table key.<br />
------------------------------------------------------------------------------------<br />
--]]<br />
function p.isNan(v)<br />
if type(v) == 'number' and tostring(v) == '-nan' then<br />
return true<br />
else<br />
return false<br />
end<br />
end<br />
<br />
--[[<br />
------------------------------------------------------------------------------------<br />
-- shallowClone<br />
--<br />
-- This returns a clone of a table. The value returned is a new table, but all<br />
-- subtables and functions are shared. Metamethods are respected, but the returned<br />
-- table will have no metatable of its own.<br />
------------------------------------------------------------------------------------<br />
--]]<br />
function p.shallowClone(t)<br />
local ret = {}<br />
for k, v in pairs(t) do<br />
ret[k] = v<br />
end<br />
return ret<br />
end<br />
<br />
--[[<br />
------------------------------------------------------------------------------------<br />
-- removeDuplicates<br />
--<br />
-- This removes duplicate values from an array. Non-positive-integer keys are<br />
-- ignored. The earliest value is kept, and all subsequent duplicate values are<br />
-- removed, but otherwise the array order is unchanged.<br />
------------------------------------------------------------------------------------<br />
--]]<br />
function p.removeDuplicates(t)<br />
checkType('removeDuplicates', 1, t, 'table')<br />
local isNan = p.isNan<br />
local ret, exists = {}, {}<br />
for i, v in ipairs(t) do<br />
if isNan(v) then<br />
-- NaNs can't be table keys, and they are also unique, so we don't need to check existence.<br />
ret[#ret + 1] = v<br />
else<br />
if not exists[v] then<br />
ret[#ret + 1] = v<br />
exists[v] = true<br />
end<br />
end <br />
end<br />
return ret<br />
end <br />
<br />
--[[<br />
------------------------------------------------------------------------------------<br />
-- numKeys<br />
--<br />
-- This takes a table and returns an array containing the numbers of any numerical<br />
-- keys that have non-nil values, sorted in numerical order.<br />
------------------------------------------------------------------------------------<br />
--]]<br />
function p.numKeys(t)<br />
checkType('numKeys', 1, t, 'table')<br />
local isPositiveInteger = p.isPositiveInteger<br />
local nums = {}<br />
for k, v in pairs(t) do<br />
if isPositiveInteger(k) then<br />
nums[#nums + 1] = k<br />
end<br />
end<br />
table.sort(nums)<br />
return nums<br />
end<br />
<br />
--[[<br />
------------------------------------------------------------------------------------<br />
-- affixNums<br />
--<br />
-- This takes a table and returns an array containing the numbers of keys with the<br />
-- specified prefix and suffix. For example, for the table<br />
-- {a1 = 'foo', a3 = 'bar', a6 = 'baz'} and the prefix "a", affixNums will<br />
-- return {1, 3, 6}.<br />
------------------------------------------------------------------------------------<br />
--]]<br />
function p.affixNums(t, prefix, suffix)<br />
checkType('affixNums', 1, t, 'table')<br />
checkType('affixNums', 2, prefix, 'string', true)<br />
checkType('affixNums', 3, suffix, 'string', true)<br />
<br />
local function cleanPattern(s)<br />
-- Cleans a pattern so that the magic characters ()%.[]*+-?^$ are interpreted literally.<br />
s = s:gsub('([()%%.%[%]*+-?^$])', '%%%1')<br />
return s<br />
end<br />
<br />
prefix = prefix or ''<br />
suffix = suffix or ''<br />
prefix = cleanPattern(prefix)<br />
suffix = cleanPattern(suffix)<br />
local pattern = '^' .. prefix .. '([1-9]%d*)' .. suffix .. '$'<br />
<br />
local nums = {}<br />
for k, v in pairs(t) do<br />
if type(k) == 'string' then <br />
local num = mw.ustring.match(k, pattern)<br />
if num then<br />
nums[#nums + 1] = tonumber(num)<br />
end<br />
end<br />
end<br />
table.sort(nums)<br />
return nums<br />
end<br />
<br />
--[[<br />
------------------------------------------------------------------------------------<br />
-- numData<br />
--<br />
-- Given a table with keys like ("foo1", "bar1", "foo2", "baz2"), returns a table<br />
-- of subtables in the format <br />
-- { [1] = {foo = 'text', bar = 'text'}, [2] = {foo = 'text', baz = 'text'} }<br />
-- Keys that don't end with an integer are stored in a subtable named "other".<br />
-- The compress option compresses the table so that it can be iterated over with<br />
-- ipairs.<br />
------------------------------------------------------------------------------------<br />
--]]<br />
function p.numData(t, compress)<br />
checkType('numData', 1, t, 'table')<br />
checkType('numData', 2, compress, 'boolean', true)<br />
local ret = {}<br />
for k, v in pairs(t) do<br />
local prefix, num = mw.ustring.match(tostring(k), '^([^0-9]*)([1-9][0-9]*)$')<br />
if num then<br />
num = tonumber(num)<br />
local subtable = ret[num] or {}<br />
if prefix == '' then<br />
-- Positional parameters match the blank string; put them at the start of the subtable instead.<br />
prefix = 1<br />
end<br />
subtable[prefix] = v<br />
ret[num] = subtable<br />
else<br />
local subtable = ret.other or {}<br />
subtable[k] = v<br />
ret.other = subtable<br />
end<br />
end<br />
if compress then<br />
local other = ret.other<br />
ret = p.compressSparseArray(ret)<br />
ret.other = other<br />
end<br />
return ret<br />
end<br />
<br />
--[[<br />
------------------------------------------------------------------------------------<br />
-- compressSparseArray<br />
--<br />
-- This takes an array with one or more nil values, and removes the nil values<br />
-- while preserving the order, so that the array can be safely traversed with<br />
-- ipairs.<br />
------------------------------------------------------------------------------------<br />
--]]<br />
function p.compressSparseArray(t)<br />
checkType('compressSparseArray', 1, t, 'table')<br />
local ret = {}<br />
local nums = p.numKeys(t)<br />
for _, num in ipairs(nums) do<br />
ret[#ret + 1] = t[num]<br />
end<br />
return ret<br />
end<br />
<br />
--[[<br />
------------------------------------------------------------------------------------<br />
-- sparseIpairs<br />
--<br />
-- This is an iterator for sparse arrays. It can be used like ipairs, but can<br />
-- handle nil values.<br />
------------------------------------------------------------------------------------<br />
--]]<br />
function p.sparseIpairs(t)<br />
checkType('sparseIpairs', 1, t, 'table')<br />
local nums = p.numKeys(t)<br />
local i = 0<br />
local lim = #nums<br />
return function ()<br />
i = i + 1<br />
if i <= lim then<br />
local key = nums[i]<br />
return key, t[key]<br />
else<br />
return nil, nil<br />
end<br />
end<br />
end<br />
<br />
--[[<br />
------------------------------------------------------------------------------------<br />
-- size<br />
--<br />
-- This returns the size of a key/value pair table. It will also work on arrays,<br />
-- but for arrays it is more efficient to use the # operator.<br />
------------------------------------------------------------------------------------<br />
--]]<br />
function p.size(t)<br />
checkType('size', 1, t, 'table')<br />
local i = 0<br />
for k in pairs(t) do<br />
i = i + 1<br />
end<br />
return i<br />
end<br />
<br />
return p</div>T12