web-dev-qa-db-fra.com

Choisissez un élément au hasard dans une table

Mon objectif est de choisir un élément aléatoire d'une table à Lua.

C’est ce que j’ai eu jusqu’à présent, mais cela ne fonctionne pas actuellement:

local myTable = { 'a', 'b', 'c', 'd' }
print( myTable[ math.random( 0, #myTable - 1 ) ] )

Comment puis-je réparer le code ci-dessus afin qu'il fonctionne comme prévu? (Ou quelle autre méthode pourrais-je utiliser?)

28
Zen

Lua indexe les tables de 1, contrairement à C, Java, etc. qui indexe les tableaux de 0. Cela signifie que dans votre table, les index valides sont: 1, 2, 3, 4. Vous recherchez les éléments suivants:

print( myTable[ math.random( #myTable ) ] )

Lorsqu'il est appelé avec un argument, math.random(n) renvoie un entier aléatoire compris entre 1 et n, y compris.

60
Michal Kottman

Je pense que la question a également besoin d'une réponse plus générale. Il n'y a pas de limite au nombre de tables lua à construire avec une séquence d'entiers commençant par 1. Les clés peuvent être vraiment n'importe quoi - il peut même s'agir d'autres tables lua! Dans de tels cas, des fonctions telles que #myTable peuvent donner une réponse inattendue (lorsqu'elles sont utilisées sans fonctionnalité métatable personnalisée). Le seul moyen fiable d'obtenir toutes les clés d'une table consiste à effectuer une itération dessus:

-- 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)]]

J'ajouterai également que la solution originale de Michal Kottman fonctionnerait parfaitement si toutes vos clés sont une séquence de nombres commençant par 1. Cela se produit chaque fois que vous créez une table en tant que myTable = {'a','b','c'}. Donc, dans les situations où les tables sont construites de cette façon, obtenir des éléments aléatoires serait plus rapide.

11
ahmadh

Tester:

t = {'a', 'b', 'c'}
print(t[0])

donne nil. En fait, 0 est hors limites (essayez t[20]) ... donc aléatoire doit être compris entre 1 et #myTable (inclusif) car le premier élément d'une table est étiqueté (indexé) comme étant 1 si vous écrivez seulement exp, voir Constructeur de table (" Enfin, les champs de la forme exp sont équivalents à [i] = exp, où i sont des entiers consécutifs commençant par 1. ").

Si vous passez à math.random seulement un argument n, vous obtenez un nombre aléatoire compris entre 1 et n inclus. Cela corrige votre exemple:

print(myTable[math.random(#myTable)])
1
ShinTakezou

J'utilise personnellement la fonction suivante inspirée par @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
0
Blincer