lua-users home
lua-l archive

[Date Prev][Date Next][Thread Prev][Thread Next] [Date Index] [Thread Index]



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/