[Date Prev][Date Next][Thread Prev][Thread Next]
[Date Index]
[Thread Index]
- Subject: Re: Question about erasing tables
- From: nobody <nobody+lua-list@...>
- Date: Mon, 3 Jul 2017 21:57:44 +0200
On 2017-07-03 21:04, J Doe wrote:
As a side question of that - how do people model a table or
array-type structure that has nils ? Is a sentinel value like 0
used instead ?
One way is to have a field that stores the length. (You can set a
metamethod to return that field instead of computing the length.)
Common names for that field are 'n', 'len', 'size', … – these do not
interfere with the array contents, as the array's keys are integers and
so you can clearly tell them apart from any metadata that you include
with e.g. string keys.
The simplest way to create an array with a "logical size" is
table.pack( 5, 23, nil, 42, nil, nil )
--> { [1] = 5, [2] = 23, [4] = 42, n = 6 }
and a simple(-ish) way to pack that up is
local _iter = function( t, k )
k = k + 1
if k <= t.n then return k, t[k] end
end
Array = {
fromValues = function( ... )
return setmetatable( table.pack( ... ), Array )
end,
fromSize = function( n )
return setmetatable( { n = n }, Array )
end,
__len = function( t ) return t.n end,
__pairs = function( t ) return _iter, t, 0 end,
}
Behold:
a = Array.fromValues( 5, 23, nil, 42, nil, nil )
print( #a )
--> 6
for k, v in pairs( a ) do print( k, v ) end
--> 1 5
2 23
3 nil
4 42
5 nil
6 nil
(If you want it to behave as if there are values everywhere, you can
additionally set
Array.__index = function( t, k )
k = tonumber( k )
if k and 0 < k and k <= t.n then return 0 end
end
and you'll get
for k, v in pairs( a ) do print( k, v ) end
--> 1 5
2 23
3 0
4 42
5 0
6 0
while still getting
a[-1], a[23]
--> nil, nil
Likewise, you could use __newidex to ensure that no out-of-bounds writes
can happen.)
A side effect of having __pairs is that metadata entries (outside of
what __pairs traverses) will be slightly harder to discover. You can
access them directly if you know their key, or do a "raw pairs":
for k, v in next, a, nil do print( k, v ) end
--> 1 5
2 23
4 42
n 6
-- nobody