• Subject: RE: [Newbie] Index a matrix with strings
• From: "Jerome Vuarand" <jerome.vuarand@...>
• Date: Thu, 8 Nov 2007 11:35:49 -0500

```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.

```