Modul:TableTools
Vində tispir
Documentation for this module may be created atModul:TableTools/doc
--[[
------------------------------------------------------------------------------------
-- 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. --
------------------------------------------------------------------------------------
--]]
locallibraryUtil=require('libraryUtil')
localp={}
-- Define often-used variables and functions.
localfloor=math.floor
localinfinity=math.huge
localcheckType=libraryUtil.checkType
--[[
------------------------------------------------------------------------------------
-- 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.
------------------------------------------------------------------------------------
--]]
functionp.isPositiveInteger(v)
iftype(v)=='number'andv>=1andfloor(v)==vandv<infinitythen
returntrue
else
returnfalse
end
end
--[[
------------------------------------------------------------------------------------
-- isNan
--
-- This function returns true if the given number is a NaN value, and false
-- if not. Although it doesn't operate on tables, it is included here as it is
-- useful for determining whether a value can be a valid table key. Lua will
-- generate an error if a NaN is used as a table key.
------------------------------------------------------------------------------------
--]]
functionp.isNan(v)
iftype(v)=='number'andtostring(v)=='-nan'then
returntrue
else
returnfalse
end
end
--[[
------------------------------------------------------------------------------------
-- shallowClone
--
-- This returns a clone of a table. The value returned is a new table, but all
-- subtables and functions are shared. Metamethods are respected, but the returned
-- table will have no metatable of its own.
------------------------------------------------------------------------------------
--]]
functionp.shallowClone(t)
localret={}
fork,vinpairs(t)do
ret[k]=v
end
returnret
end
--[[
------------------------------------------------------------------------------------
-- removeDuplicates
--
-- This removes duplicate values from an array. Non-positive-integer keys are
-- ignored. The earliest value is kept, and all subsequent duplicate values are
-- removed, but otherwise the array order is unchanged.
------------------------------------------------------------------------------------
--]]
functionp.removeDuplicates(t)
checkType('removeDuplicates',1,t,'table')
localisNan=p.isNan
localret,exists={},{}
fori,vinipairs(t)do
ifisNan(v)then
-- NaNs can't be table keys, and they are also unique, so we don't need to check existence.
ret[#ret+1]=v
else
ifnotexists[v]then
ret[#ret+1]=v
exists[v]=true
end
end
end
returnret
end
--[[
------------------------------------------------------------------------------------
-- numKeys
--
-- This takes a table and returns an array containing the numbers of any numerical
-- keys that have non-nil values, sorted in numerical order.
------------------------------------------------------------------------------------
--]]
functionp.numKeys(t)
checkType('numKeys',1,t,'table')
localisPositiveInteger=p.isPositiveInteger
localnums={}
fork,vinpairs(t)do
ifisPositiveInteger(k)then
nums[#nums+1]=k
end
end
table.sort(nums)
returnnums
end
--[[
------------------------------------------------------------------------------------
-- affixNums
--
-- This takes a table and returns an array containing the numbers of keys with the
-- specified prefix and suffix. For example, for the table
-- {a1 = 'foo', a3 = 'bar', a6 = 'baz'} and the prefix "a", affixNums will
-- return {1, 3, 6}.
------------------------------------------------------------------------------------
--]]
functionp.affixNums(t,prefix,suffix)
checkType('affixNums',1,t,'table')
checkType('affixNums',2,prefix,'string',true)
checkType('affixNums',3,suffix,'string',true)
localfunctioncleanPattern(s)
-- Cleans a pattern so that the magic characters ()%.[]*+-?^$ are interpreted literally.
s=s:gsub('([%(%)%%%.%[%]%*%+%-%?%^%$])','%%%1')
returns
end
prefix=prefixor''
suffix=suffixor''
prefix=cleanPattern(prefix)
suffix=cleanPattern(suffix)
localpattern='^'..prefix..'([1-9]%d*)'..suffix..'$'
localnums={}
fork,vinpairs(t)do
iftype(k)=='string'then
localnum=mw.ustring.match(k,pattern)
ifnumthen
nums[#nums+1]=tonumber(num)
end
end
end
table.sort(nums)
returnnums
end
--[[
------------------------------------------------------------------------------------
-- numData
--
-- 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".
-- The compress option compresses the table so that it can be iterated over with
-- ipairs.
------------------------------------------------------------------------------------
--]]
functionp.numData(t,compress)
checkType('numData',1,t,'table')
checkType('numData',2,compress,'boolean',true)
localret={}
fork,vinpairs(t)do
localprefix,num=mw.ustring.match(tostring(k),'^([^0-9]*)([1-9][0-9]*)$')
ifnumthen
num=tonumber(num)
localsubtable=ret[num]or{}
ifprefix==''then
-- Positional parameters match the blank string; put them at the start of the subtable instead.
prefix=1
end
subtable[prefix]=v
ret[num]=subtable
else
localsubtable=ret.otheror{}
subtable[k]=v
ret.other=subtable
end
end
ifcompressthen
localother=ret.other
ret=p.compressSparseArray(ret)
ret.other=other
end
returnret
end
--[[
------------------------------------------------------------------------------------
-- compressSparseArray
--
-- This takes an array with one or more nil values, and removes the nil values
-- while preserving the order, so that the array can be safely traversed with
-- ipairs.
------------------------------------------------------------------------------------
--]]
functionp.compressSparseArray(t)
checkType('compressSparseArray',1,t,'table')
localret={}
localnums=p.numKeys(t)
for_,numinipairs(nums)do
ret[#ret+1]=t[num]
end
returnret
end
--[[
------------------------------------------------------------------------------------
-- sparseIpairs
--
-- This is an iterator for sparse arrays. It can be used like ipairs, but can
-- handle nil values.
------------------------------------------------------------------------------------
--]]
functionp.sparseIpairs(t)
checkType('sparseIpairs',1,t,'table')
localnums=p.numKeys(t)
locali=0
locallim=#nums
returnfunction()
i=i+1
ifi<=limthen
localkey=nums[i]
returnkey,t[key]
else
returnnil,nil
end
end
end
--[[
------------------------------------------------------------------------------------
-- size
--
-- This returns the size of a key/value pair table. It will also work on arrays,
-- but for arrays it is more efficient to use the # operator.
------------------------------------------------------------------------------------
--]]
functionp.size(t)
checkType('size',1,t,'table')
locali=0
forkinpairs(t)do
i=i+1
end
returni
end
returnp