求闻百科
搜索
切换搜索
切换菜单
切换个人菜单
查看“Module:TableTools/sandbox”的源代码
求闻百科,共笔求闻
模块
讨论
更多操作
←
Module:TableTools/sandbox
因为下列原因,您没有权限编辑该页面。请逐条确认下列问题是否解决后再试。
您所请求的操作,仅限具有
注册用户
权限的
用户
执行。
若您尚未登录求闻百科账号,请您
登录
求闻百科账号后操作。
您尚未完成实名制验证,因此操作受限。请尽快
完成实名制验证
,或联系
裁决委员会
以
获取操作权限
。
注:若您是非中国大陆用户,您应当联络电子邮件staff
qiuwen.org以获得帮助。
您尚未完成
电子邮件确认
,因此操作受限,请尽快
完成电子邮件确认
。
若您无法完成前述手续,请参考
帮助文档
,或通过适当渠道请求管理员或裁决委员协助。
根据《中华人民共和国网络安全法》规定,您必须
登录您的账号
才能编辑求闻百科页面。
若您无法完成前述手续,请通过适当渠道请求管理员或裁决委员协助。
您可以查看和复制此页面的源代码。
若您无权编辑本页面,您可以
提出编辑请求
,提请有权限者代为编辑。
--[[ ------------------------------------------------------------------------------------ -- 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. -- ------------------------------------------------------------------------------------ --]] local libraryUtil = require('libraryUtil') local p = {} -- Define often-used variables and functions. local floor = math.floor local infinity = math.huge local checkType = libraryUtil.checkType local checkTypeMulti = libraryUtil.checkTypeMulti --[[ ------------------------------------------------------------------------------------ -- 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. ------------------------------------------------------------------------------------ --]] function p.isPositiveInteger(v) return type(v) == 'number' and v >= 1 and floor(v) == v and v < infinity 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. ------------------------------------------------------------------------------------ --]] function p.isNan(v) return not rawequal(v,v) end -- 浅复制一个表。 function p.shallowClone(t) local ret = {} for k, v in pairs(t) do ret[k] = v end return ret end function p.shallowCloneArray(t) local ret = {} for k, v in ipairs(t) do ret[k] = v end return ret end -- 浅复制一个表,但是忽略元表。 function p.rawShallowClone(t) local ret for _, v in next, t do ret[t] = v end return ret end -- 往数组追加另一个数组的值。 function p.appendAll(t, another) for _, v in ipairs(another) do t[#t + 1] = v end end -- 从数组中移除重复值。 function p.removeDuplicates(t) local ret, exists = {}, {} for i, v in ipairs(t) do if not rawequal(v, 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 if not exists[v] then ret[#ret + 1] = v exists[v] = true end end end return ret end -- 返回有非nil值的数字键的表。 function p.numKeys(t) local isPositiveInteger = p.isPositiveInteger local nums = {} for k, v in pairs(t) do if isPositiveInteger(k) then nums[#nums + 1] = k end end table.sort(nums) return nums end -- 返回含有所有数字键的表,包括小数、负数。 function p.allNumKeys(t) local nums = {} for k, v in pairs(t) do if type(k)=='number' then nums[#nums + 1] = k end end table.sort(nums) return nums end local function cleanPattern(s) -- Cleans a pattern so that the magic characters ()%.[]*+-?^$ are interpreted literally. return s:gsub('([%(%)%%%.%[%]%*%+%-%?%^%$])', '%%%1') end -- 搜索指定前后缀的整数键。 function p.affixNums(t, prefix, suffix) prefix = prefix or '' suffix = suffix or '' prefix = cleanPattern(prefix) suffix = cleanPattern(suffix) local pattern = '^' .. prefix .. '([1-9]%d*)' .. suffix .. '$' local nums = {} for k, v in pairs(t) do if type(k) == 'string' then local num = mw.ustring.match(k, pattern) if num then nums[#nums + 1] = tonumber(num) end end end table.sort(nums) return nums end --搜索指定前后缀的所有数字键,不限于整数。 function p.allAffixNums(t, prefix, suffix) prefix = cleanPattern(prefix or '') suffix = cleanPattern(suffix or '') local pattern = string.format('^%s(.-)%s$', prefix, suffix) local nums = {} for k, v in pairs(t) do if type(k) == 'string' then nums[#nums + 1] = tonumber(mw.ustring.match(k, pattern)) end end table.sort(nums) end -- 将有("foo1", "bar1", "foo2", "baz2")这样键的表转换成 -- { [1] = {foo = 'text', bar = 'text'}, [2] = {foo = 'text', baz = 'text'} } -- compress函数用来压实表以便用ipairs迭代。 function p.numData(t, compress) checkType('numData', 1, t, 'table') local ret = {} for k, v in pairs(t) do local prefix, num = mw.ustring.match(tostring(k), '^([^0-9]*)([1-9][0-9]*)$') if num then num = tonumber(num) local subtable = ret[num] or {} if prefix == '' 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 local subtable = ret.other or {} subtable[k] = v ret.other = subtable end end if compress then local other = ret.other ret = p.compressSparseArray(ret) ret.other = other end return ret end -- 将像{a1='a1',b1='b1',a2='a2'}这样的表转换成 -- {a = {'a1', 'a2'}, b = {'b1'}} -- 注意可能是稀疏数组。 -- pattern是正则表达式,匹配前缀和数字。 function p.allPrefixedNumKeys(t, pattern) local ret = {} for k, v in pairs(t) do local prefix, num = mw.ustring.match(tostring(k), pattern or '^([^0-9]*)([1-9][0-9]*)$') num = tonumber(num) if prefix and num then local subtable = ret[prefix] or {} subtable[num] = v ret[prefix] = subtable end end return ret end -- 将稀疏数组压实,移除nil值。 function p.compressSparseArray(t) checkType('compressSparseArray', 1, t, 'table') local ret = {} local nums = p.numKeys(t) for _, num in ipairs(nums) do ret[#ret + 1] = t[num] end return ret end -- 将所有键为数字的字段转化成按数字大小排序的数组。 function p.compressExtendedSparseArray(t) checkType('compressExtendedSparseArray', 1, t, 'table') local ret = {} local nums = p.allNumKeys(t) for _, num in ipairs(nums) do ret[#ret + 1] = t[num] end return ret end function p.sparseIpairs(t) checkType('sparseIpairs', 1, t, 'table') local nums = p.numKeys(t) local i = 0 local lim = #nums return function () i = i + 1 if i <= lim then local key = nums[i] return key, t[key] else return nil, nil end end end function p.extendedSparseIpairs(t) checkType('extendedSparseIpairs', 1, t, 'table') local nums = p.allNumKeys(t) local i = 0 local lim = #nums return function () i = i + 1 if i <= lim then local key = nums[i] return key, t[key] else return nil, nil end end end -- 返回表中字段的数量。 function p.size(t) checkType('size', 1, t, 'table') local i = 0 for k in pairs(t) do i = i + 1 end return i end -- 返回表中字段的数量,但是忽略元表。 function p.rawSize(t) checkType('rawSize', 1, t, 'table') local i = 0 for k in next, t do i = i + 1 end return i end local function defaultKeySort(item1, item2) -- "number" < "string", so numbers will be sorted before strings. local type1, type2 = type(item1), type(item2) if type1 ~= type2 then return type1 < type2 else -- This will fail with table, boolean, function. return item1 < item2 end end -- 返回表中的键的列表,并使用默认比较函数或者自定义keySort函数比较。 function p.keysToList(t, keySort, checked) if not checked then checkType('keysToList', 1, t, 'table') checkTypeMulti('keysToList', 2, keySort, { 'function', 'boolean', 'nil' }) end local list = {} local index = 1 for key, value in pairs(t) do list[index] = key index = index + 1 end if keySort ~= false then keySort = type(keySort) == 'function' and keySort or defaultKeySort table.sort(list, keySort) end return list end -- 返回表中的键的列表,并使用默认比较函数或者自定义keySort函数比较,但是忽略元表。 function p.rawKeysToList(t, keySort, checked) if not checked then checkType('keysToList', 1, t, 'table') checkTypeMulti('keysToList', 2, keySort, { 'function', 'boolean', 'nil' }) end local list = {} local index = 1 for key, value in next, t do list[index] = key index = index + 1 end if keySort ~= false then keySort = type(keySort) == 'function' and keySort or defaultKeySort table.sort(list, keySort) end return list end -- 排序后迭代。 function p.sortedPairs(t, keySort) checkType('sortedPairs', 1, t, 'table') checkType('sortedPairs', 2, keySort, 'function', true) local list = p.keysToList(t, keySort, true) local i = 0 return function() i = i + 1 local key = list[i] if key ~= nil then return key, t[key] else return nil, nil end end end -- 排序后迭代,但是忽略元表。 function p.rawSortedPairs(t, keySort) checkType('sortedPairs', 1, t, 'table') checkType('sortedPairs', 2, keySort, 'function', true) local list = p.rawKeysToList(t, keySort, true) local i = 0 return function() i = i + 1 local key = list[i] if key ~= nil then return key, t[key] else return nil, nil end end end -- 判断一个表是否为严格的数组。 function p.isArray(t) checkType("isArray", 1, t, "table") local i = 0 for k, v in pairs(t) do i = i + 1 if t[i] == nil then return false end end return true end -- { "a", "b", "c" } -> { a = 1, b = 2, c = 3 } function p.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 p.listToSet(t) checkType("listToSet", 1, t, "table") local set = {} for _, item in ipairs(t) do set[item] = true end return set end -- 递归深度拷贝,保护标识和子表。 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) already_seen[mt] = mt_copy end end else -- number, string, boolean, etc copy = orig 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) end -- sparseConcat{ a, nil, c, d } => "acd" -- sparseConcat{ nil, b, c, d } => "bcd" function p.sparseConcat(t, sep, i, j) local list = {} local list_i = 0 for _, v in p.sparseIpairs(t) do list_i = list_i + 1 list[list_i] = v end return table.concat(list, sep, i, j) end function p.inArray(arr, valueToFind) checkType("inArray", 1, arr, "table") for _, v in ipairs(arr) do if v == valueToFind then return true end end return false end function p.visit(t,notNum) local keys = {} for k, v in pairs(t) do if type(k)=="number" then table.insert(keys,k) else if notNum then notNum(k,v,keys,t) end end end local i = 0 return function() i = i+1 return keys[i],key[i] and t[keys[i]] end end 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 return p