[Date Prev][Date Next][Thread Prev][Thread Next]
[Date Index]
[Thread Index]
- Subject: Re: Proposal for table length operator
- From: Renato Maia <maia@...>
- Date: Tue, 14 Dec 2010 19:58:58 -0200
On 14 Dec 2010, at 02:03, Keith Matthews wrote:
I think that a big part of the problem is that people feel 'nil'
should somehow be treated differently from other values when storing
it in a table used as an array.
That's because 'nil' is indeed different from other values since it
means precisely the absence of a value (e.g. uninitialized variables,
parameters not provided). Personally, what I think is a big part of
the problem may be that people feel tables should somehow replace for
all other data structures --- sure they do a great job as maps, lists,
records and sets --- but tables are more like the simplest and most
fundamental building block of data structures in Lua. You use them to
create the data structures you need, like sorted maps or sparse
arrays. For example, to get something similar to what you want, you
could do:
---------------------------------------8
<---------------------------------------
-- [[ sparse.lua ]]
local _G = require "_G"
local rawset = _G.rawset
local select = _G.select
local setmetatable = _G.setmetatable
local table = require "table"
local unpack = table.unpack or _G.unpack
local lengthOf = setmetatable({}, {__mode="k"})
local meta = {}
function meta:__newindex(index, value)
if index > lengthOf[self] then
lengthOf[self] = index
end
rawset(self, index, value)
end
function meta:__len()
return lengthOf[self]
end
local function iterator(self, index)
if index < lengthOf[self] then
index = index+1
return index, self[index]
end
end
function meta:__ipairs()
return iterator, self, 0
end
local sparse = {length=meta.__len, ipairs=meta.__ipairs}
function sparse.create(...)
local self = {...}
lengthOf[self] = select("#", ...)
return setmetatable(self, meta)
end
function sparse:remove(index)
local length = lengthOf[self]
if index == nil then index = length end
if index > 0 and index <= length then
local value = self[index]
for i = index+1, length do
self[i-1] = self[i]
end
self[length] = nil
lengthOf[self] = length-1
return value
end
end
function sparse:unpack()
return unpack(self, 1, lengthOf[self])
end
return sparse
---------------------------------------8
<---------------------------------------
--[[ test assuming Lua 5.2 alpha ]]
local sparse = require "sparse"
do
local t = sparse.create()
assert(select("#", sparse.remove(t)) == 0)
assert(select("#", sparse.remove(t, 1)) == 0)
assert(#t == 0)
for i,v in ipairs(t) do
assert(false)
end
t[10] = nil
assert(#t == 10)
t[20] = nil
assert(#t == 20)
t[30] = nil
assert(#t == 30)
assert(select("#", sparse.remove(t, 5)) == 1)
assert(#t == 29)
assert(select("#", sparse.remove(t, 15)) == 1)
assert(#t == 28)
assert(select("#", sparse.remove(t, 25)) == 1)
assert(#t == 27)
assert(select("#", sparse.remove(t, 35)) == 0)
assert(#t == 27)
local ok
for i,v in ipairs(t) do
ok = assert(i>0 and i<=27 and i%1==0)
assert(v == nil)
end
assert(ok)
end
do
local t = sparse.create(1, nil, 3)
assert(#t == 3)
end
do
local t = sparse.create(1, nil, 3, nil)
assert(#t == 4)
end
do
local t = sparse.create()
t[1000] = "thousand"
assert(#t == 1000)
assert(sparse.remove(t) == "thousand")
assert(#t == 999)
local ok
for i,v in ipairs(t) do
ok = assert(i>0 and i<1000 and i%1==0)
assert(v == nil)
end
assert(ok)
end
do
local t = sparse.create()
t[1000] = "thousand"
assert(#t == 1000)
assert(select("#", sparse.remove(t, 1)) == 1)
assert(#t == 999)
assert(t[999] == "thousand")
assert(t[1000] == nil)
end
do
local t = sparse.create(1, 2, 3)
t[#t] = nil
assert(#t == 3)
assert(select("#", sparse.unpack(t)) == 3)
local a, b, c = sparse.unpack(t)
assert(a == 1)
assert(b == 2)
assert(c == nil)
end
do
local t = sparse.create(1, 2, 3)
assert(sparse.remove(t) == 3)
assert(#t == 2)
assert(select("#", sparse.unpack(t)) == 2)
local a, b = sparse.unpack(t)
assert(a == 1)
assert(b == 2)
end
--
Renato Maia
Computer Scientist
Tecgraf/PUC-Rio
__________________________
http://www.inf.puc-rio.br/~maia/