My goal is to pick out a random item from a table in Lua.
This is what I've got so far, but it currently does not work:
local myTable = { 'a', 'b', 'c', 'd' }
print( myTable[ math.random( 0, #myTable - 1 ) ] )
How can I fix the above code so that it works as intended? (Or which other method could I use?)
Lua indexes tables from 1, unlike C, Java etc. which indexes arrays from 0. That means, that in your table, the valid indexes are: 1, 2, 3, 4. What you are looking for is the following:
print( myTable[ math.random( #myTable ) ] )
When called with one argument, math.random(n)
returns a random integer from 1 to n
including.
I think the question also needs a more general answer. There is no limitation on lua tables to be built with a sequence of integers starting from 1. Keys can be really anything - they could even be other lua tables! In such cases, functions like #myTable might give an answer you don't expect (when used without any custom metatable functionality). The only reliable way to get all keys in a table is to iterate over it:
-- iterate over whole table to get all keys
local keyset = {}
for k in pairs(myTable) do
table.insert(keyset, k)
end
-- now you can reliably return a random key
random_elem = myTable[keyset[math.random(#keyset)]]
I will also add that the original solution by Michal Kottman would work perfectly if all your keys are a sequence of numbers starting from 1. This happens whenever you create a table as myTable = {'a','b','c'}
. So for situations where tables are built this way, getting random elements from the table would be faster his way.
Test:
t = {'a', 'b', 'c'}
print(t[0])
gives nil
. In fact 0 is out of bounds (try t[20]
)... so random must be from 1 to #myTable
(inclusive) because the first element of a table is labeled (indexed) as 1 if you write just exp
, see Table constructor ("Finally, fields of the form exp are equivalent to [i] = exp, where i are consecutive integers starting with 1.").
If you pass to math.random just an argument n
, you obtain a random number from 1 to n
inclusive. This fixes your example:
print(myTable[math.random(#myTable)])
I personally use the following function inspired by @ahmadh
function random_elem(tb)
local keys = {}
for k in pairs(tb) do table.insert(tb, k) end
return tb[keys[math.random(#keys)]]
end