122 votes

Comment vérifier si un tableau contient un élément en Lua ?

Existe-t-il une méthode permettant de vérifier si un tableau contient une valeur ? J'ai ma propre fonction (naïve), mais je me demandais si quelque chose d'"officiel" existe pour cela ? Ou quelque chose de plus efficace...

function table.contains(table, element)
  for _, value in pairs(table) do
    if value == element then
      return true
    end
  end
  return false
end

À propos, la raison principale pour laquelle j'utilise cette fonction est d'utiliser les tableaux comme des ensembles, c'est-à-dire sans éléments en double. Y a-t-il quelque chose d'autre que je puisse utiliser ?

3 votes

Que signifie la notation _, ?

26 votes

C'est simplement une variable "poubelle" nommée _ . pairs() renvoie à key, value mais dans cet exemple, je n'ai besoin que de la valeur. C'est une sorte de convention (adoptée dans le livre "Programming in Lua") lua.org/pil/index.html ) pour utiliser ce _ variable pour stocker les choses dont vous n'avez pas besoin.

0 votes

J'ai vu la convention de nommer les variables "poubelles". _ utilisé en Python et en JavaScript, également.

137voto

interjay Points 51000

Vous pouvez mettre les valeurs comme clés de la table. Par exemple :

function addToSet(set, key)
    set[key] = true
end

function removeFromSet(set, key)
    set[key] = nil
end

function setContains(set, key)
    return set[key] ~= nil
end

Il existe un exemple plus complet. aquí .

14 votes

Un utilisateur anonyme a proposé la correction suivante à votre code : Si la valeur du set avec la clé spécifiée est FALSE, alors la fonction setContains() retourne un false bien qu'il y ait un élément dans la table avec la clé spécifiée. La ligne "return set[key] ~= nil" corrige cette erreur.

1 votes

Peut-être aussi function keysOfSet(set) local ret={} for k,_ in pairs(set) do ret[#ret+1]=k end return ret end

26voto

Norman Ramsey Points 115730

Compte tenu de votre représentation, votre fonction est aussi efficace que possible. Bien sûr, comme l'ont fait remarquer d'autres personnes (et comme cela se pratique dans des langages plus anciens que Lua), la solution à votre vrai problème est de changer de représentation. Quand vous avez des tableaux et que vous voulez des ensembles, vous transformez les tableaux en ensembles en utilisant l'élément ensemble comme clé et true comme valeur. +1 à interjay.

0 votes

Une méthode "officielle" le ferait probablement en C, ce qui serait plus rapide. Mais si c'est fait uniquement en lua, comme vous l'avez dit, c'est la méthode la plus efficace possible !

3voto

James Points 1

Je sais que c'est un vieux post, mais je voulais ajouter quelque chose pour la postérité. La façon simple de traiter le problème que vous avez est de faire une autre table, de valeur à clé.

Par exemple, vous avez deux tables qui ont la même valeur, l'une pointant dans une direction, l'autre dans l'autre.

function addValue(key, value)
    if (value == nil) then
        removeKey(key)
        return
    end
    _primaryTable[key] = value
    _secodaryTable[value] = key
end

function removeKey(key)
    local value = _primaryTable[key]
    if (value == nil) then
        return
    end
    _primaryTable[key] = nil
    _secondaryTable[value] = nil
end

function getValue(key)
    return _primaryTable[key]
end

function containsValue(value)
    return _secondaryTable[value] ~= nil
end

Vous pouvez ensuite interroger la nouvelle table pour voir si elle contient la clé "élément". Cela évite d'avoir à itérer sur chaque valeur de l'autre table.

S'il s'avère que vous ne pouvez pas utiliser l'"élément" comme clé, parce qu'il ne s'agit pas d'une chaîne de caractères, par exemple, ajoutez une somme de contrôle ou une clé de sécurité. tostring sur elle par exemple, et ensuite l'utiliser comme clé.

Pourquoi voulez-vous faire ça ? Si vos tables sont très grandes, le temps d'itération de chaque élément sera important, ce qui vous empêchera de le faire très souvent. La surcharge mémoire supplémentaire sera relativement faible, car il s'agira de stocker deux pointeurs vers le même objet, plutôt que deux copies du même objet. Si vos tables sont très petites, alors cela aura beaucoup moins d'importance, en fait il peut même être plus rapide d'itérer que d'avoir une autre consultation de carte.

Le libellé de la question suggère toutefois fortement que vous avez un grand nombre d'éléments à traiter.

0 votes

Une bonne explication, mais qui n'ajoute pas vraiment quelque chose à la discussion. Il aurait probablement été préférable d'éditer la réponse d'interjay.

1 votes

De même, '.key' devrait être remplacé par '[key]' partout dans ce code (de même que 'value').

2voto

Roque Points 141
-- in some helper module
function utils_Set(list)
    local set = {}
    for _, l in ipairs(list) do set[l] = true end
    return set
end

-- your table here
long_table = { "v1", "v2", "v1000"}

-- Consult some value
_set = utils_Set(long_table)
if _set["v1"] then print("yes!") end

2voto

Joel Points 3899

Je ne vois pas d'autre moyen de comparer des valeurs, mais si vous utilisez l'élément de l'ensemble comme clé, vous pouvez donner à la valeur toute autre chose que nil. Vous obtenez alors des recherches rapides sans avoir à chercher dans toute la table.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X