Register forum user name Search FAQ

Gammon Forum

Notice: Any messages purporting to come from this site telling you that your password has expired, or that you need to verify your details, confirm your email, resolve issues, making threats, or asking for money, are spam. We do not email users with any such messages. If you have lost your password you can obtain a new one by using the password reset link.

Due to spam on this forum, all posts now need moderator approval.

 Entire forum ➜ MUSHclient ➜ Lua ➜ How do you guys Test for NIL values when dealing with a lot of nested arrays?

How do you guys Test for NIL values when dealing with a lot of nested arrays?

It is now over 60 days since the last post. This thread is closed.     Refresh page


Posted by Mendaloth   (14 posts)  Bio
Date Wed 23 Nov 2011 07:27 PM (UTC)

Amended on Wed 23 Nov 2011 07:40 PM (UTC) by Mendaloth

Message
I am wondering what is the best way or how do you guys normally deal with testing to see if an array is nil.

Take my current example. I have an array with a bunch subarrays:
filter_settings['clan_settings'][clan_name]['selected'] = "Y"
filter_settings['clan_settings'][clan_name]['player_clan'] = "Y"

There are 3 or 4 different functions that either change these values or display them for the user so there is no guarantee that it is not NIL.

I know anytime I access or change an array I can test if it is nil, and then create the array if it does not already exist. I don't like that approach in the above case because I end up having to do a lot of ifs. Even if I assume the clan_settings array already exists within the filter_settings array, I still have to check if filter_settings['clan_settings'][clan_name] is nil, and then if either filter_settings['clan_settings'][clan_name]['selected']/['player_clan'] are nil.

Doing this 3 or 4 times gets messy.

I came up with the idea of just testing to see if the filter_settings['clan_settings'][clan_name] is nil, and if it is nil then filling the array with default values for every clan OnPluginInstall. This works for now, but if I later decide I want to add a third value like filter_settings['clan_settings'][clan_name]['never_select'] then my plugin will have to back in and go through every clan name and make sure there is a default value for the never_select. If I end up adding a few different values after I first published the plugin then it ends up looking like a mess.

Am I missing a third option, or an easier way of doing this?
Top

Posted by Nick Gammon   Australia  (23,140 posts)  Bio   Forum Administrator
Date Reply #1 on Wed 23 Nov 2011 08:31 PM (UTC)

Amended on Wed 23 Nov 2011 08:47 PM (UTC) by Nick Gammon

Message
In your case you really only have one variable, clan_name. That is, I assume you start off with:

filter_settings.clan_settings
being a table that exists.


After that you only really need one line


filter_settings.clan_settings [clan_name] = filter_settings.clan_settings [clan_name] or {}


That guarantees that clan's table exists. Now you can just do:


filter_settings.clan_settings.[clan_name].player_clan = "Y"


Where, of course, player_clan being nil means the same as no. In which case you are better off using booleans:


filter_settings.clan_settings.[clan_name].player_clan = true


Then you can say:


if filter_settings.clan_settings.[clan_name].player_clan then
  --  player has a clan
end -- if


... because the absence of the variable (ie. nil) is the same as false.

- Nick Gammon

www.gammon.com.au, www.mushclient.com
Top

Posted by Nick Gammon   Australia  (23,140 posts)  Bio   Forum Administrator
Date Reply #2 on Wed 23 Nov 2011 08:46 PM (UTC)

Amended on Wed 23 Nov 2011 08:51 PM (UTC) by Nick Gammon

Message
Or you can simplify things for yourself by making a metatable.




-- set up tables:

filter_settings = {}
filter_settings.clan_settings = {}

mt = { __index = 
     function (tbl, key) 
       tbl [key] = {}    -- add sub table
       return tbl [key]  -- return as missing value
     end }

setmetatable (filter_settings.clan_settings, mt)


What this does is (assuming you have the tables filter_settings and clan_settings set up initially), detects if you attempt to access a non-existent clan, and add that clan to the table on-the-fly.

Now you can just access the new clan:



clan_name = "foo"

filter_settings.clan_settings [clan_name].selected = true

require "tprint"
tprint (filter_settings)


Output:


"clan_settings":
  "foo":
    "selected"=true




- Nick Gammon

www.gammon.com.au, www.mushclient.com
Top

Posted by Twisol   USA  (2,257 posts)  Bio
Date Reply #3 on Wed 23 Nov 2011 08:59 PM (UTC)

Amended on Wed 23 Nov 2011 09:02 PM (UTC) by Twisol

Message
You could also try using a function to go down a chain of tables, inserting new ones if necessary.

function table_set_chain(tbl, k, v, next, ...)
  if type(tbl) ~= "table" then
    error("`" .. tostring(tbl) .. "` is not a table")
  end
  
  if next then
    local child = tbl[k]
    if not child then
      child = {}
      tbl[k] = child
    end
    return table_set_chain(child, v, next, ...)
  else
    tbl[k] = v
    return true
  end
end


Usage: table_set_chain(filter_settings, 'clan_settings', clan_name, 'selected', "Y")

Yay tail recursion.

'Soludra' on Achaea

Blog: http://jonathan.com/
GitHub: http://github.com/Twisol
Top

Posted by Mendaloth   (14 posts)  Bio
Date Reply #4 on Thu 24 Nov 2011 03:01 PM (UTC)
Message
Nick Gammon said:


Then you can say:


if filter_settings.clan_settings.[clan_name].player_clan then
  --  player has a clan
end -- if


... because the absence of the variable (ie. nil) is the same as false.



Thanks that little trick was exactly what I was missing! Works great now!
Top

The dates and times for posts above are shown in Universal Co-ordinated Time (UTC).

To show them in your local time you can join the forum, and then set the 'time correction' field in your profile to the number of hours difference between your location and UTC time.


18,390 views.

It is now over 60 days since the last post. This thread is closed.     Refresh page

Go to topic:           Search the forum


[Go to top] top

Information and images on this site are licensed under the Creative Commons Attribution 3.0 Australia License unless stated otherwise.