[Date Prev][Date Next][Thread Prev][Thread Next]
[Date Index]
[Thread Index]
- Subject: Re: Unexpected table.remove behaviour.
- From: lostgallifreyan <lostgallifreyan@...>
- Date: Wed, 24 Jun 2009 09:57:49 +0100
[Amended copy of last mail, contains comments for code I'd prepared and forgotten to edit in..]
Patrick Donnelly <batrick@batbytes.com> wrote:
(24/06/2009 04:44)
>> C:\WINDOWS\Desktop>lua
>> Lua 5.1.4 Copyright (C) 1994-2008 Lua.org, PUC-Rio
>> > x={}
>> > x[40]=5
>> > print(#x)
>> 0
>> > print(x[40])
>> 5
>> > table.remove(x,40)
>> > print(x[40])
>> 5
>> >
>>
>> Is this intentional? I notice that with Lua v4, you can do it. x[40] will be nil.
>
>It is intentional. table.remove (like table.insert) expects an array
>for its table argument. It strictly checks that the value being
>removed is within the array's bounds (that is, 1 - #t).
>
Ok, thanks, so long as it's right and not going to change unexpectedly I can cope with it somehow.
>> Here are two different scripts for same purpose of syncing two arrays according to operations carried out on one of them:
>>
>> X={0,0,0,0,0,1,1,1,1,2,2,3,4,5,5,5,5,5,6,6,6,6,6,6,6,6,7,8,8,8,8,8,8,8,8,8,9,9,9,9}
>> Y={}
>> for N=#X,1,-1 do
>> Y[N]=N
>> if X[N]==X[N+1] then table.remove(X,N+1) table.remove(Y,N+1) end
>> end
>> print(unpack(X))
>> print(unpack(Y))
>>
>> X={0,0,0,0,0,1,1,1,1,2,2,3,4,5,5,5,5,5,6,6,6,6,6,6,6,6,7,8,8,8,8,8,8,8,8,8,9,9,9,9}
>> Y={}
>> for N=getn(X),1,-1 do
>> Y[N]=N
>> if X[N]==X[N+1] then tremove(X,N+1) tremove(Y,N+1) end
>> end
>> for N=1,getn(X) do print(X[N]) end
>> for N=1,getn(Y) do print(Y[N]) end
>>
[snip..]
>I would use this code to get your "sync" behavior above (If I
>understand the intent correctly):
>
>X={0,0,0,0,0,1,1,1,1,2,2,3,4,5,5,5,5,5,6,6,6,6,6,6,6,6,7,8,8,8,8,8,8,8,8,8,9,9,9,9}
>Y = {}
>for i, v in ipairs(X) do
> Y[i] = v;
> while X[i+1] == v do table.remove(X, i+1); end
>end
>
Nope. :) If it worked, the table Y would contain the ten indices at which the values in table X had changed, (as seen in an upward count). Also, the reason I work backward is to overcome the #t value being fetched at iterator start, not re-evaluated at each iteration. If I work backwards I know I won't eventually run into errors based on trying to operate on nil values as #t decreases. Also, the speed of traversing large tables increases as less elements have to be moved, as the bulk of removal is done well before I reach the top of the table. This lets me operate on data in place rather than via intermediate or temporary tables, which I find ugly. So even if there IS a way to do it forwards, it's likely not desirable. Would be nice if ipairs() could iterate backwards, but nothing wrong with a decrementing for loop...
>> PS. I notices 'setn' is deprecated. If I wanted to do it, can it be done some other way, and if so, how?
>
>When I have needed to set the length of a table manually, I have used
>key 'n' in the table. An example of how it can be used is gathering
>the return values of a function in a table:
>
>function pack (...)
> return {n = select("#", ...), ...}
>end
>
That's a nice construct but weirdly, it's not necessary so long as n is copied from #t before anything else is done to that table. If you're providing every element, regardless of nil values present, the # is set to the number of arguments added anyway, and my table.remove(x,40) works. I just tested this.. If you just hand the arguments as comma-separated values inside T={x,y,x,nil,nil,1,2,3,...} you get a table with # equal to the number of values, and table.remove works on any element, as expected, at least it does the FIRST time, as then the # value changes to (first nil element)-1. Further, if you declare an empty table and populate it later, this secondary behaviour occurs at the outset because # remains 0 if the first value is nil. Two snippets to illustrate:
x={nil,nil,nil,nil,nil,nil,nil,nil,nil,nil,nil,nil,nil,nil,nil,nil,nil,nil,nil,nil,nil,nil,nil,nil,nil,nil,nil,nil,nil,nil,nil,nil,nil,nil,nil,nil,nil,nil,nil} --39 nils
x[40]=5
print(#x) --40!
print(x[40]) --5
table.remove(x,10)
print(x[40]) --nil
print(x[39]) --5
print(#x) --0
x={}
for n=1,39 do x[n]=nil end
x[40]=5
print(#x) --0!
print(x[40]) --5
table.remove(x,10)
print(x[40]) --5
print(x[39]) --nil
print(#x) --0
To solve my case I do need to iterate backwards as I described earlier, but I might be ok because the initial table to which others must be synced is full of values and no holes so I can use its # value at any time, and if it weren't I could always do a for loop to fill an empty table with empty strings or 0's to make # work at all times, though this last 'fix' isn't the kind of neatness and power I've come to value in Lua. :)
Above all, I like that I can make an array in a table and populate negative indices with values with the positive indices, accessed by simple arithmetical sign to choose which of the pair to use, or add arbitrary key/value pairs without affecting the array (ipairs() function) behaviour. I find that extremely elegant and strong, and I hope that isn't going to change. It looks like I've found a quirk that might imply that something is going to change though..