'Lua - Creating a lookup table that handles a nil value?

I have one Lua table that I want to use as a look up for another table, and while I can get it to work when there is a matching ID/key, I can’t make handle blanks (entries with no key to map.)

To explain what I mean, I create the follow room number/ID to room name table this way..

local room_index = {}
for i,n in pairs (luup.rooms) do
    room_index[i] = n
end

Which creates the following..

{ [1]="Kitchen", [2]="Outside", [3]="Living Room", [4]="Front Room", [5]="Office", [6]="Hallway", [7]="Conservatory", [8]="Landing", [9]="Emma's Room", [10]="Lean To", [11]="Back Landing", [12]="Front Landing", [13]="Boiler Room", [14]="Loft Landing", [15]="Ben's Room", [16]="Main Bedroom", [17]="Under Stairs" } 

I then I look to the a devices table to show which device is in which room.

for i,d in pairs(luup.devices) do
    local r = d.room_num
 print(room_index[r], d.description)
end

Which creates the following ..

Office     ZRC-90U Controller     
Kitchen     TKB Energy     
nil     Home Energy Meter Gen5     
nil     Clamp 1     
Living Room     Living Room Media     
nil     WWN Home/Away - Home     
Under Stairs     Under Stairs Temp     
Under Stairs     Under Stairs Power     
Living Room     TV Headphones     

The problem I have is that I can’t work out how to handle the nil values, where there is not an Room number/ID associated with the device, how do I handle this? Rather than nil, I’d just like it to say "No Room"

I looked at various other SO posts, which seem quite complex. Surely this is something relatively straight forward when doing look up tables ? It’s like I need a default [nil]="No Room" entry somewhere?

lua


Solution 1:[1]

If you really want your table to return "No Room" when indexed with nil, you can implement that using a metatable:

setmetatable(room_index, {__index = function(self, key)
    if key == nil then return "No Room" end
end})

Be warned that this may increase the error-proneness of your application: Something like room_index[uninitialized_variable] will return "No Room" as well.

Solution 2:[2]

While it is possible to index a table with nil (see the other answer), I don't think it's the best solution to the issue, or a clean solution at all. Lua uses nil in a few special places when iterating through a table, and using it for something meaningful is counterintuitive.

If all you want is to be able to turn nil into a custom text, you don't have to use a metatable for that; use a function:

function room_name(index)
  if index then
    return room_index[index]
  end
  return "No Room"
end

Or, if it could make sense to represent a "No Room" entity as an actual entity, for other purposes, just use a non-nil value:

local no_room = -1

room_index[no_room] = "No Room"

for i,d in pairs(luup.devices) do
  local r = d.room_num
  print(room_index[r or no_room], d.description)
end

Or, if you cannot assume that -1 be an invalid index, use a string or {} to index it; it's all the same to Lua.

Solution 3:[3]

In this particular situation the table I was doing the look ups from, stored devices with no room associated with a 0 (zero), so in the end I could use that.

local room_index = {}
for i,n in pairs (luup.rooms) do
    room_index[i] = n
end

print (pretty(room_index))

for i,d in pairs(luup.devices) do
    local r = d.room_num
    if r ~= 0 then print(room_index[r], d.description)
        else print ("No Room", d.description)
    end
end

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1 LMD
Solution 2 IS4
Solution 3