WoWInterface

WoWInterface (https://www.wowinterface.com/forums/index.php)
-   Lua/XML Help (https://www.wowinterface.com/forums/forumdisplay.php?f=16)
-   -   Removing a table key? (https://www.wowinterface.com/forums/showthread.php?t=49866)

zork 09-09-14 07:34 AM

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.

Quote:

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?

p3lim 09-09-14 07:39 AM

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

zork 09-09-14 07:51 AM

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?!

Choonstertwo 09-09-14 08:00 AM

Quote:

Originally Posted by zork (Post 296432)
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.

p3lim 09-09-14 08:01 AM

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.

Phanx 09-09-14 09:06 AM

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.

Duugu 09-09-14 10:01 AM

Quote:

Originally Posted by Phanx (Post 296436)
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!

zork 09-09-14 10:08 AM

Thank you.

Sharparam 09-09-14 11:14 AM

Quote:

Originally Posted by Phanx (Post 296436)
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)
>


Phanx 09-09-14 01:58 PM

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. :p

Phanx 09-12-14 03:00 AM

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.

zork 09-12-14 04:47 AM

If I have a table referenced by indexes [1], [2] and [3].

If I table.remove(t,2).

[3] becomes [2] right?

Lombra 09-12-14 04:50 AM

Yes. tinsert and tremove will both automatically adjust the array appropriately. (unlike just setting nil)


All times are GMT -6. The time now is 02:17 AM.

vBulletin © 2020, Jelsoft Enterprises Ltd
© 2004 - 2020 MMOUI