34

In Lua, there seem to be two ways of appending an element to an array:

table.insert(t, i)

and

t[#t+1] = i

Which should I use, and why?

Sled
  • 18,541
  • 27
  • 119
  • 168
Eric
  • 95,302
  • 53
  • 242
  • 374

4 Answers4

44

Which to use is a matter of preference and circumstance: as the # length operator was introduced in version 5.1, t[#t+1] = i will not work in Lua 5.0, whereas table.insert has been present since 5.0 and will work in both. On the other hand, t[#t+1] = i uses exclusively language-level operators, wheras table.insert involves a function (which has a slight amount of overhead to look up and call and depends on the table module in the environment).

In the second edition of Programming in Lua (an update of the Lua 5.0-oriented first edition), Roberto Ierusalimschy (the designer of Lua) states that he prefers t[#t+1] = i, as it's more visible.


Also, depending on your use case, the answer may be "neither". See the manual entry on the behavior of the length operator:

If the array has "holes" (that is, nil values between other non-nil values), then #t can be any of the indices that directly precedes a nil value (that is, it may consider any such nil value as the end of the array).

As such, if you're dealing with an array with holes, using either one (table.insert uses the length operator) may "append" your value to a lower index in the array than you want. How you define the size of your array in this scenario is up to you, and, again, depends on preference and circumstance: you can use table.maxn (disappearing in 5.2 but trivial to write), you can keep an n field in the table and update it when necessary, you can wrap the table in a metatable, or you could use another solution that better fits your situation (in a loop, a local tsize in the scope immediately outside the loop will often suffice).

Stuart P. Bentley
  • 10,195
  • 10
  • 55
  • 84
  • 1
    My suggestion for Lua 5.3 is to add vector array construction operator [ ] like mixed array construction operator { }. This new operator will have `maxn` and `size` fields internally, where `maxn` will be accessible through `#` length operator and `size` through `array.size(t)` or `t:size()`. – happy_marmoset Oct 09 '13 at 08:27
  • 1
    @happy_marmoset: If you need that behavior, you can implement it with what already exists in 5.2 (just set a metatable that adds those properties). – Stuart P. Bentley Oct 09 '13 at 22:52
6

The following is slightly on the amusing side but possibly with a grain of aesthetics. Even though there are obvious reasons that mytable:operation() is not supplied like mystring:operation(), one can easily roll one's own variant, and get a third notation if desired.

Table = {}
Table.__index = table                     

function Table.new()
   local t = {}
   setmetatable(t, Table)
   return t
end

mytable = Table.new()
mytable:insert('Hello')
mytable:insert('World')
for _, s in ipairs(mytable) do
   print(s)
end
Sled
  • 18,541
  • 27
  • 119
  • 168
AndersH
  • 808
  • 6
  • 7
  • 2
    Sorry, but it's not so obvious to me. Is it a performance consideration? Or backwards compatibility? – Sled Jul 09 '18 at 15:48
2

insert can insert arbitrarily (as its name states), it only defaults to #t + 1, where as t[#t + 1] = i will always append to the (end of the) table. see section 5.5 in the lua manual.

Necrolis
  • 25,836
  • 3
  • 63
  • 101
  • I'm aware of the fact that insert can take extra arguments. My question is why I would use the two argument version over `t[#t + 1] = i` – Eric May 24 '11 at 15:34
  • 3
    @Eric: If your variable is not named t, but myVeryDescriptiveLongNameOfMyGloballyVisibleArray then it saves keystrokes :-) – AndersH May 31 '11 at 19:26
  • 2
    `(function(t) t[#t+1] = i end)(myVeryDescriptiveLongNameOfMyGloballyVisibleArray)` – Will May 17 '13 at 21:54
1

'#' operator only use indexed key table.

t = {1, 2 ,3 ,4, 5, x=1, y=2}

at above code

print(#t)  --> print 5 not 7

'#' operator whenever not using.

If you want to '#' operator, then check it to table elements type.

Insert function can using any type use.But element count to work slow than '#'

gogothing
  • 309
  • 3
  • 7