lua-users home
lua-l archive

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


Jerome Vuarand wrote:
> Eike Decker wrote:
>>> Can you specify how you want to access your matrix?
>> 
>> like
>> 
>> mymatrix["bar"]["tex"] = "x"
>> 
>> or
>> 
>> mymatrix[1][2] = "foo"
> 
> The normal solution is to allocate intermediate tables yourself:
> 
> mymatrix["bar"] = {}
> mymatrix["bar"]["tex"] = "x"
> mymatrix[1] = {}
> mymatrix[1][2] = "foo"
> 
> The magic solution is to automtically create a subtable when you
> access your root table. To do that use metatables: 
> 
> mymatrix = setmetatable({}, {
>     __index = function(t,k)
>         local subt = {}
>         t[k] = subt
>         return subt
>     end
> })
> 
> mymatrix["bar"]["tex"] = "x"
> mymatrix[1][2] = "foo"

I sent the mail too early. I forgot to mention that the second solution has a drawback. If you access your matrix with a single index it will always create a subtable. For example:

mymatrix["bar"]["tex"] = "x"
mymatrix[1][2] = "foo"

print(mymatrix["bar"]["tex"]) --> x
print(mymatrix[1][2]) --> foo
print(mymatrix[37]) --> table: 0x01234567

You cannot know in the index metamethod whether there is a second indexation coming in or not. One solution is to use compound indices, and do a single indexation, like proposed in the PiL. For example:

-- with string, nothing to do
mymatrix = {}

mymatrix["bar:tex"] = "x"
mymatrix["1:2"] = "foo"

print(mymatrix["bar:tex"]) --> x
print(mymatrix["1:2"]) --> foo
print(mymatrix["3:4"]) --> nil

-- with tables, need a proxy table
mymatrix = setmetatable({}, {
	data = {},
    __newindex = function(t,k,v)
		local data = getmetatable(t).data
		assert(type(k)=='table')
		local i,j = k[1],k[2]
		assert(i~=nil and j~=nil)
		data[i] = data[i] or {}
		data[i][j] = v
    end,
    __index = function(t,k)
		local data = getmetatable(t).data
		if type(k)=='table' then
			local i,j = k[1],k[2]
			assert(i~=nil and j~=nil)
			if not data[i] then return nil end
			return data[i][j]
		else
			return nil
		end
    end
})

mymatrix[{"bar", "tex"}] = "x"
mymatrix[{1,2}] = "foo"

print(mymatrix[{"bar", "tex"}]) --> x
print(mymatrix[{1,2}]) --> foo
print(mymatrix[{3,4}]) --> nil

Again a drawback is that iteration over the table might not work like you expect. There may be other solutions in that case.