2

When testing code with both a predefined script and the LUA runtime environment, LUA will not take any form of string key values. However, if a numerical value key is used LUA will work with it as intended. The exception to this rule when I am using Tshark with a LUA file to parse packet captures. This allows the string key value syntax to work normally. Is there something I may be performing wrong?

I have tried creating several .lua script files with different variations including:

testArray.NewItem = "value1" testArray["NewItem"] = "value1"

NewItemValue = "NewItem" testArray[NewItemValue] = "value1"

These all result in an nil value or an error due to trying to call a nil value depending on the return style used to check.

> tcpstream = {}
> stream1 = tostring(14356)
> tcpstream[stream1] = "nothing"
> print(#tcpstream)
0
> print(tcpstream[1])
nil
> tcpstream[1] = "nothing"
> print(#tcpstream)
1
> print(tcpstream[1])
nothing

the output of the print(#tcpstream) after the tcpstream[stream1] = "nothing" should show 1 not zero. The subsequent print(tcpstream[1]) should also show "nothing".

2 Answers2

3

From http://lua-users.org/wiki/TablesTutorial

The # operator doesn't count all the items in the table (!). Instead it finds the last integer (non-fractional number) key. Because of how it's implemented its results are undefined if all the integer keys in the table aren't consecutive. Which is why it shouldn't be used for tables used as sparse arrays[2]).

The '#' is not a good(sometimes not correct) way to count the number of elements in Lua table.

As for

> stream1 = tostring(14356)
> tcpstream[stream1] = "nothing"
> print(#tcpstream)
0
> print(tcpstream[1])
nil

Lua uses key,value pairs, not explicitly index. If you do 'arr[1] = 22', it means the value for the key '1' is 22, not the value for the first element is 22.

Brad Pitt
  • 398
  • 3
  • 11
  • Your reference is correct for the version of Lua at the time of writing. The reference manual for the current version gives a different description. Obviously, one should use the reference manual for the version begin used. If `#` is used on tables it is designed for, it is good and correct. – Tom Blodget Jul 26 '19 at 22:27
0

The length operator(#) does not work as you believe, this is a common mistake for beginners in Lua.

The default behavior for #sometable is to return the number of consecutive key starting at the number 1(or after any nil value for 5.3). String keys are never evaluated with the default # operator for a table.

In 5.3 if your sequence contains multiple nil values the behavior of # is non-deterministic.

Lua 5.3 Reference Manual: 3.4.7 – The Length Operator

Lua 5.1 Reference Manual: 2.5.5 – The Length Operator

I will include the lines from 5.1 as i feel it covers the information regarding the operator and tables well. While note identical to how 5.3 work it maybe easier to understand why you see the behavior you do.

2.5.5 – The Length Operator The length operator is denoted by the unary operator #. The length of a string is its number of bytes (that is, the usual meaning of string length when each character is one byte).

The length of a table t is defined to be any integer index n such that t[n] is not nil and t[n+1] is nil; moreover, if t1 is nil, n can be zero. For a regular array, with non-nil values from 1 to a given n, its length is exactly that n, the index of its last value. 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).

Here are some examples of different table and their # results:

table1 = { --number keys in array
  true,
  true,
  true,
}
table2 = { -- number keys in hash
  [1] = true,
  [2] = true,
  [3] = true,
}
table3 = { -- only strings as key
  ['1'] = true,
  ['2'] = true,
  ['3'] = true,
}
table4 = { -- No key 2 defined
  [1] = true,
  -- [2] = true, 
  [3] = true,
}
table5 = { -- table with both string and number keys
  [1] = true,
  ['2'] = true,
}
print(#table1) -- 3
print(#table2) -- 3
print(#table3) -- 0
print(#table4) -- v5.3(1 or 3) v5.1(1)
print(#table5) -- 1
Nifim
  • 4,758
  • 2
  • 12
  • 31
  • "number of consecutive key starting at the number 1": this contradicts the 5.1 reference that you quoted. – Tom Blodget Jul 26 '19 at 22:29
  • @TomBlodget I have made the statement bold from the manual which supports my claim. If that line does not clear up the contradiction, I may need more information to understand the contradiction you are referring to. – Nifim Jul 26 '19 at 22:37
  • `#{"one", "two", "three", nil, "five", nil, "seven"}` Per your description, this would be 3. Per 5.1, it could be any integer >= 0. Per 5.3, it could be 3, 5, or 7. In short, # is misapplied to such a table. – Tom Blodget Jul 26 '19 at 22:44
  • @TomBlodget 5.3 is non-deterministic and i have now clarified that. I am still working to address the 5.1 comment. – Nifim Jul 26 '19 at 23:52