Module:TableTools: Difference between revisions
Content added Content deleted
(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 |
-- 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( |
function p.isPositiveInteger(v) |
||
if type( |
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 |
||
⚫ | |||
--[[ |
|||
------------------------------------------------------------------------------------ |
|||
-- 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 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 |
|||
⚫ | |||
-- 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 |
if lim < 2 then |
||
error( |
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 |
||
-- 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 |
|||
⚫ | |||
⚫ | |||
end |
end |
||
⚫ | |||
⚫ | |||
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 |
||
⚫ | |||
-- 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 |
|||
⚫ | |||
ret[#ret + 1] = val |
ret[#ret + 1] = val |
||
end |
end |