Thread Tools Display Modes
09-09-14, 07:34 AM   #1
zork
A Pyroguard Emberseer
 
zork's Avatar
AddOn Author - Click to view addons
Join Date: Jul 2008
Posts: 1,740
Removing a table key?

Assuming I want to save guids. At some point in the future I want to remove outdated guids.

Lua Code:
  1. local guids = {}
  2.  
  3. local guidA = "12345"
  4. local guidB = "ABCDE"
  5.  
  6. guids[guidA] = { time=time(), hp=UnitHealth(guidA) }
  7. guids[guidB] = { time=time(), hp=UnitHealth(guidB) }
*edit* Just found what I was looking for in the last sentence.

Note that table.remove only works with numeric indexes. For dictionaries you can just unset tables entries with tablevariable["index"] = nil; http://lua-users.org/wiki/TableLibraryTutorial
So I guess I will do this
Lua Code:
  1. for k,v in ipairs(guids) do
  2.   if time()-3600 > v.time then
  3.     guids[k] = nil
  4.   end
  5. end

Question. If I set the table value for a key to nil. When ipairs is called again. Will ipairs return keys with a value of nil?
__________________
| Simple is beautiful.
| WoWI AddOns | GitHub | Zork (WoW)

"I wonder what the non-pathetic people are doing tonight?" - Rajesh Koothrappali (The Big Bang Theory)

Last edited by zork : 09-09-14 at 07:46 AM.
  Reply With Quote
09-09-14, 07:39 AM   #2
p3lim
A Pyroguard Emberseer
 
p3lim's Avatar
AddOn Author - Click to view addons
Join Date: Feb 2007
Posts: 1,710
table.remove is used to remove values from an indexed array, not a a associative array like yours, the usage of it is this:
Code:
table.remove(guids, index)
Use this instead:
Code:
guids[guidA] = nil
  Reply With Quote
09-09-14, 07:51 AM   #3
zork
A Pyroguard Emberseer
 
zork's Avatar
AddOn Author - Click to view addons
Join Date: Jul 2008
Posts: 1,740
Yeah updated my post. Found it in the last sentence of the lib tutorial.
When running ipairs on a table with keys that are set to nil. Are those entries still returned? I mean the key should still exist?!
__________________
| Simple is beautiful.
| WoWI AddOns | GitHub | Zork (WoW)

"I wonder what the non-pathetic people are doing tonight?" - Rajesh Koothrappali (The Big Bang Theory)
  Reply With Quote
09-09-14, 08:00 AM   #4
Choonstertwo
A Chromatic Dragonspawn
 
Choonstertwo's Avatar
AddOn Author - Click to view addons
Join Date: Jan 2011
Posts: 194
Originally Posted by zork View Post
Yeah updated my post. Found it in the last sentence of the lib tutorial.
When running ipairs on a table with keys that are set to nil. Are those entries still returned? I mean the key should still exist?!
Keys don't "exist" in tables unless they have a non-nil value. In the internals of Lua there may be some difference between a key with a nil value and a key without a value; but this difference isn't exposed in the language.

ipairs iterates until it hits a nil value and then stops. If keys 1, 2, 3 and 5 of your table have values, ipairs will iterate up to 3 and then stop.

Last edited by Choonstertwo : 09-09-14 at 08:06 AM.
  Reply With Quote
09-09-14, 08:01 AM   #5
p3lim
A Pyroguard Emberseer
 
p3lim's Avatar
AddOn Author - Click to view addons
Join Date: Feb 2007
Posts: 1,710
Setting the value to nil effectively removes the key from the table.

Also, ipairs halts when it hits the first nil value (and it can't read the key afaik), and it also is slower than any other option.
Use pairs, or better yet, next for your iteration needs.

Code:
local t = {
    [1] = true,
    [2] = nil,
    [3] = false
}

for k, v in ipairs(t) do
    print('ipairs', k, v)
end

-- prints [1] = true

for k, v in next, t do
    print('next', k, v)
end

-- prints [1] = true, [3] = false
ipairs is basically the equivalent of a for loop for associative arrays, and should only be used if necessary.

Last edited by p3lim : 09-09-14 at 08:10 AM.
  Reply With Quote
09-09-14, 09:06 AM   #6
Phanx
Cat.
 
Phanx's Avatar
AddOn Author - Click to view addons
Join Date: Mar 2006
Posts: 5,617
Even better on an indexed table (and much faster than either pairs or next):

Code:
for i = 1, #t do
    local v = t[i]
    -- do stuff here
end
Using ipairs is never necessary. It doesn't do anything the above method doesn't do, but it is much slower. I don't even know why ipairs exists.
__________________
Retired author of too many addons.
Message me if you're interested in taking over one of my addons.
Don’t message me about addon bugs or programming questions.
  Reply With Quote
09-09-14, 10:01 AM   #7
Duugu
Premium Member
 
Duugu's Avatar
AddOn Author - Click to view addons
Join Date: Nov 2006
Posts: 851
Originally Posted by Phanx View Post
Even better on an indexed table (and much faster than either pairs or next)
So true. Changed that a few days ago with a large table that was iterated a lot and gained ~ 30-40 percent performance!
  Reply With Quote
09-09-14, 10:08 AM   #8
zork
A Pyroguard Emberseer
 
zork's Avatar
AddOn Author - Click to view addons
Join Date: Jul 2008
Posts: 1,740
Thank you.
__________________
| Simple is beautiful.
| WoWI AddOns | GitHub | Zork (WoW)

"I wonder what the non-pathetic people are doing tonight?" - Rajesh Koothrappali (The Big Bang Theory)
  Reply With Quote
09-09-14, 11:14 AM   #9
Sharparam
A Flamescale Wyrmkin
 
Sharparam's Avatar
AddOn Author - Click to view addons
Join Date: Oct 2011
Posts: 102
Originally Posted by Phanx View Post
Using ipairs is never necessary. It doesn't do anything the above method doesn't do, but it is much slower. I don't even know why ipairs exists.
It might be worth mentioning they are not exactly equivalent (but the cases when they aren't are very rare special cases). As mentioned in a comment to this StackOverflow answer.

Example when a table has "holes":

Code:
ILUA: Lua 5.1.4  Copyright (C) 1994-2008 Lua.org, PUC-Rio
"quit" to end

> t = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10}
> #t
10
> for i, v in ipairs(t) do io.write(v .. " ") end print() -- traditional for loop would have the same result
1 2 3 4 5 6 7 8 9 10

> t = {[1] = 1, [2] = 2, [4] = 4, [5] = 5}
> #t
5
> for i, v in ipairs(t) do io.write(v .. " ") end print()
1 2
> for i = 1, #t do io.write(t[i] .. " ") end print()
1 2 [string "local"]:1: attempt to concatenate field '?' (a nil value)
>
  Reply With Quote
09-09-14, 01:58 PM   #10
Phanx
Cat.
 
Phanx's Avatar
AddOn Author - Click to view addons
Join Date: Mar 2006
Posts: 5,617
That's true, but if you're using an indexed table and putting holes in it and still expecting to use it as an indexed table, you are Doing It Wrong.
__________________
Retired author of too many addons.
Message me if you're interested in taking over one of my addons.
Don’t message me about addon bugs or programming questions.
  Reply With Quote
09-12-14, 03:00 AM   #11
Phanx
Cat.
 
Phanx's Avatar
AddOn Author - Click to view addons
Join Date: Mar 2006
Posts: 5,617
Also another thing that occurred to me is that either method (ipairs or #) will end up skipping values if you remove values inside the loop... but # has the advantage here (yet again) in that you can do the loop backwards to avoid this.

Code:
print("ipairs")
local t = { "apple", "banana", "coconut", "durian" }
for i, v in ipairs(t) do
    print(i, v)
    if i == 2 then
        tremove(t, i)
    end
end
You only get "apple", "banana", and "durian" printed, and the loop doesn't even iterate a 4th time.

Code:
print("#")
local t = { "apple", "banana", "coconut", "durian" }
for i = 1, #t do
    local v = t[i]
    print(i, v)
    if i == 2 then
        tremove(t, i)
    end
end
You still only get "apple", "banana", and "durian" but the loop does iterate a 4th time and you get a "nil" print.

Code:
print("# reverse")
local t = { "apple", "banana", "coconut", "durian" }
for i = #t, 1, -1 do
    local v = t[i]
    print(i, v)
    if i == 2 then
        tremove(t, i)
    end
end
Now you get all 4 values printed.
__________________
Retired author of too many addons.
Message me if you're interested in taking over one of my addons.
Don’t message me about addon bugs or programming questions.
  Reply With Quote
09-12-14, 04:47 AM   #12
zork
A Pyroguard Emberseer
 
zork's Avatar
AddOn Author - Click to view addons
Join Date: Jul 2008
Posts: 1,740
If I have a table referenced by indexes [1], [2] and [3].

If I table.remove(t,2).

[3] becomes [2] right?
__________________
| Simple is beautiful.
| WoWI AddOns | GitHub | Zork (WoW)

"I wonder what the non-pathetic people are doing tonight?" - Rajesh Koothrappali (The Big Bang Theory)
  Reply With Quote
09-12-14, 04:50 AM   #13
Lombra
A Molten Giant
 
Lombra's Avatar
AddOn Author - Click to view addons
Join Date: Nov 2006
Posts: 554
Yes. tinsert and tremove will both automatically adjust the array appropriately. (unlike just setting nil)
__________________
Grab your sword and fight the Horde!
  Reply With Quote

WoWInterface » Developer Discussions » Lua/XML Help » Removing a table key?

Thread Tools
Display Modes

Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

vB code is On
Smilies are On
[IMG] code is On
HTML code is Off