Editing Module:TableTools
The edit can be undone. Please check the comparison below to verify that this is what you want to do, and then publish the changes below to finish undoing the edit.
Latest revision | Your text | ||
Line 17: | Line 17: | ||
local infinity = math.huge | local infinity = math.huge | ||
local checkType = libraryUtil.checkType | local checkType = libraryUtil.checkType | ||
--[[ | --[[ | ||
Line 30: | Line 29: | ||
--]] | --]] | ||
function p.isPositiveInteger(v) | function p.isPositiveInteger(v) | ||
if type(v) == 'number' and v >= 1 and floor(v) == v and v < infinity then | |||
return true | |||
else | |||
return false | |||
end | |||
end | end | ||
Line 44: | Line 47: | ||
--]] | --]] | ||
function p.isNan(v) | function p.isNan(v) | ||
if type(v) == 'number' and tostring(v) == '-nan' then | |||
return true | |||
else | |||
return false | |||
end | end | ||
end | end | ||
Line 89: | Line 79: | ||
end | end | ||
return ret | return ret | ||
end | end | ||
--[[ | |||
------------------------------------------------------------------------------------ | |||
-- union | |||
-- | |||
-- This returns the union of the key/value pairs of n tables. If any of the tables | |||
-- contain different values for the same table key, the table value is converted | |||
-- to an array holding all of the different values. | |||
------------------------------------------------------------------------------------ | |||
--]] | |||
function p.union(...) | |||
local lim = select('#', ...) | |||
if lim < 2 then | |||
error("too few arguments to 'union' (minimum is 2, received " .. lim .. ')', 2) | |||
end | |||
local ret, trackArrays = {}, {} | |||
for i = 1, lim do | |||
local t = select(i, ...) | |||
checkType('union', i, t, 'table') | |||
for k, v in pairs(t) do | |||
local retKey = ret[k] | |||
if retKey == nil then | |||
ret[k] = v | |||
elseif retKey ~= v then | |||
if trackArrays[k] then | |||
local array = ret[k] | |||
local valExists | |||
for _, arrayVal in ipairs(array) do | |||
if arrayVal == v then | |||
valExists = true | |||
break | |||
end | |||
end | |||
if not valExists then | |||
array[#array + 1] = v | |||
ret[k] = array | |||
end | |||
else | |||
ret[k] = {ret[k], v} | |||
trackArrays[k] = true | |||
end | |||
end | |||
end | |||
end | |||
return ret | |||
end | |||
--[[ | |||
------------------------------------------------------------------------------------ | |||
-- valueUnion | |||
-- | |||
-- This returns the union of the values of n tables, as an array. For example, for | |||
-- the tables {1, 3, 4, 5, foo = 7} and {2, bar = 3, 5, 6}, union will return | |||
-- {1, 2, 3, 4, 5, 6, 7}. | |||
------------------------------------------------------------------------------------ | |||
--]] | |||
function p.valueUnion(...) | |||
local lim = select('#', ...) | |||
if lim < 2 then | |||
error("too few arguments to 'valueUnion' (minimum is 2, received " .. lim .. ')', 2) | |||
end | |||
local isNan = p.isNan | |||
local ret, exists = {}, {} | |||
for i = 1, lim do | |||
local t = select(i, ...) | |||
checkType('valueUnion', i, t, 'table') | |||
for k, v in pairs(t) do | |||
if isNan(v) then | |||
ret[#ret + 1] = v | |||
elseif not exists[v] then | |||
ret[#ret + 1] = v | |||
exists[v] = true | |||
end | |||
end | |||
end | |||
return ret | |||
end | |||
--[[ | |||
------------------------------------------------------------------------------------ | |||
-- intersection | |||
-- | |||
-- This returns the intersection of the key/value pairs of n tables. Both the key | |||
-- and the value must match to be included in the resulting table. | |||
------------------------------------------------------------------------------------ | |||
--]] | |||
function p.intersection(...) | |||
local lim = select('#', ...) | |||
if lim < 2 then | |||
error("too few arguments to 'intersection' (minimum is 2, received " .. lim .. ')', 2) | |||
end | |||
local ret, track, pairCounts = {}, {}, {} | |||
for i = 1, lim do | |||
local t = select(i, ...) | |||
checkType('intersection', i, t, 'table') | |||
for k, v in pairs(t) do | |||
local trackVal = track[k] | |||
if trackVal == nil then | |||
track[k] = v | |||
pairCounts[k] = 1 | |||
elseif trackVal == v then | |||
pairCounts[k] = pairCounts[k] + 1 | |||
end | |||
end | |||
end | |||
for k, v in pairs(track) do | |||
if pairCounts[k] == lim then | |||
ret[k] = v | |||
end | |||
end | |||
return ret | |||
end | |||
--[[ | |||
------------------------------------------------------------------------------------ | |||
-- valueIntersection | |||
-- | |||
-- This returns the intersection of the values of n tables, as an array. For | |||
-- example, for the tables {1, 3, 4, 5, foo = 7} and {2, bar = 3, 5, 6}, | |||
-- intersection will return {3, 5}. | |||
------------------------------------------------------------------------------------ | |||
--]] | |||
function p.valueIntersection(...) | |||
local lim = select('#', ...) | |||
if lim < 2 then | |||
error("too few arguments to 'valueIntersection' (minimum is 2, received " .. lim .. ')', 2) | |||
end | |||
local isNan = p.isNan | |||
local vals, ret = {}, {} | |||
local isSameTable = true -- Tracks table equality. | |||
local tableTemp -- Used to store the table from the previous loop so that we can check table equality. | |||
for i = 1, lim do | |||
local t = select(i, ...) | |||
checkType('valueIntersection', i, t, 'table') | |||
if tableTemp and t ~= tableTemp then | |||
isSameTable = false | |||
end | |||
tableTemp = t | |||
for k, v in pairs(t) do | |||
-- NaNs are never equal to any other value, so they can't be in the intersection. | |||
-- Which is lucky, as they also can't be table keys. | |||
if not isNan(v) then | |||
local valCount = vals[v] or 0 | |||
vals[v] = valCount + 1 | |||
end | |||
end | |||
end | |||
if isSameTable then | |||
-- If all the tables are equal, then the intersection is that table (including NaNs). | |||
-- All we need to do is convert it to an array and remove duplicate values. | |||
for k, v in pairs(tableTemp) do | |||
ret[#ret + 1] = v | |||
end | |||
return p.removeDuplicates(ret) | |||
end | |||
for val, count in pairs(vals) do | |||
if count == lim then | |||
ret[#ret + 1] = val | |||
end | |||
end | |||
return ret | |||
end | |||
--[[ | |||
------------------------------------------------------------------------------------ | |||
-- complement | |||
-- | |||
-- This returns the relative complement of t1, t2, ..., in tn. The complement | |||
-- is of key/value pairs. This is equivalent to all the key/value pairs that are in | |||
-- tn but are not in t1, t2, ... tn-1. | |||
------------------------------------------------------------------------------------ | |||
--]] | |||
function p.complement(...) | |||
local lim = select('#', ...) | |||
if lim < 2 then | |||
error("too few arguments to 'complement' (minimum is 2, received " .. lim .. ')', 2) | |||
end | |||
--[[ | |||
-- Now we know that we have at least two sets. | |||
-- First, get all the key/value pairs in tn. We can't simply make ret equal to tn, | |||
-- as that will affect the value of tn for the whole module. | |||
--]] | |||
local tn = select(lim, ...) | |||
checkType('complement', lim, tn, 'table') | |||
local ret = {} | |||
for k, v in pairs(tn) do | |||
ret[k] = v | |||
end | |||
-- Remove all the key/value pairs in t1, t2, ..., tn-1. | |||
for i = 1, lim - 1 do | |||
local t = select(i, ...) | |||
checkType('complement', i, t, 'table') | |||
for k, v in pairs(t) do | |||
if ret[k] == v then | |||
ret[k] = nil | |||
end | |||
end | |||
end | |||
return ret | |||
end | |||
--[[ | --[[ | ||
Line 126: | Line 316: | ||
checkType('affixNums', 2, prefix, 'string', true) | checkType('affixNums', 2, prefix, 'string', true) | ||
checkType('affixNums', 3, suffix, 'string', true) | checkType('affixNums', 3, suffix, 'string', true) | ||
prefix = prefix or '' | prefix = prefix or '' | ||
suffix = suffix or '' | suffix = suffix or '' | ||
local pattern = '^' .. prefix .. '([1-9]%d*)' .. suffix .. '$' | local pattern = '^' .. prefix .. '([1-9]%d*)' .. suffix .. '$' | ||
local nums = {} | local nums = {} | ||
for k, v in pairs(t) do | for k, v in pairs(t) do | ||
Line 149: | Line 330: | ||
table.sort(nums) | table.sort(nums) | ||
return nums | return nums | ||
end | end | ||
Line 229: | Line 369: | ||
local key = nums[i] | local key = nums[i] | ||
return key, t[key] | return key, t[key] | ||
end | end | ||
end | end | ||
Line 243: | Line 381: | ||
------------------------------------------------------------------------------------ | ------------------------------------------------------------------------------------ | ||
--]] | --]] | ||
function p.size(t) | function p.size(t) | ||
checkType('size', 1, t, 'table') | checkType('size', 1, t, 'table') | ||
Line 251: | Line 388: | ||
end | end | ||
return i | return i | ||
end | end | ||
return p | return p |