Module:TableTools: Difference between revisions

From Tardis Wiki, the free Doctor Who reference
2,316 bytes added ,  19 December 2013
add isNan function, shallowClone function and removeDuplicates function, fix up valueIntersection function to work properly for NaNs
(clone tn rather than returning an altered tn)
(add isNan function, shallowClone function and removeDuplicates function, fix up valueIntersection function to work properly for NaNs)
Line 25: Line 25:
-- isPositiveInteger
-- isPositiveInteger
--
--
-- This function returns true if the given number is a positive integer, and false
-- 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
-- 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
-- useful for determining whether a given table key is in the array part or the
Line 31: Line 31:
------------------------------------------------------------------------------------
------------------------------------------------------------------------------------
--]]
--]]
function p.isPositiveInteger(num)
function p.isPositiveInteger(v)
if type(num) == 'number' and num >= 1 and floor(num) == num and num < infinity then
if type(v) == 'number' and v >= 1 and floor(v) == v and v < infinity then
return true
return true
else
else
return false
return false
end
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.
------------------------------------------------------------------------------------
--]]
function p.isNan(v)
if type(v) == 'number' and tostring(v) == '-nan' then
return true
else
return false
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.
------------------------------------------------------------------------------------
--]]
function p.shallowClone(t)
local ret = {}
for k, v in pairs(t) do
ret[k] = v
end
return ret
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.
------------------------------------------------------------------------------------
--]]
function p.removeDuplicates(t)
local isNan = p.isNan
local ret, exists = {}, {}
for i, v in ipairs(t) do
if isNan(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
end


Line 167: Line 228:
function p.valueIntersection(...)
function p.valueIntersection(...)
local lim = select('#', ...)  
local lim = select('#', ...)  
if lim == 0 then
if lim < 2 then
error("no arguments passed to 'valueIntersection'", 2)
error(lim .. ' argument' .. (lim == 1 and '' or 's') .. " passed to 'intersection' (minimum is 2)", 2)
end
end
local isNan = p.isNan
local vals, ret = {}, {}
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
for i = 1, lim do
local t = select(i, ...)
local t = select(i, ...)
checkType('valueIntersection', i, t, 'table')
checkType('valueIntersection', i, t, 'table')
if tableTemp and t ~= tableTemp then
isSameTable = false
end
tableTemp = t
for k, v in pairs(t) do
for k, v in pairs(t) do
if type(v) == 'number' and tostring(v) == '-nan' then
-- NaNs are never equal to any other value, so they can't be in the intersection.
v = nan -- NaN cannot be a table key, so use a proxy variable.
-- 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
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
end
for val, count in pairs(vals) do
for val, count in pairs(vals) do
if count == lim then
if count == lim then
if val == nan then
-- This ensures that we output a NaN when we had one as input, although
-- they may have been generated in a completely different way.
val = 0/0
end
ret[#ret + 1] = val
ret[#ret + 1] = val
end
end
Cookies help us deliver our services. By using our services, you agree to our use of cookies.