Comment vérifier si une table contient un élément dans Lua?

97

Existe-t-il une méthode pour vérifier si une table contient une valeur? J'ai ma propre fonction (naïve), mais je me demandais s'il existe quelque chose d '"officiel" pour ça? 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

Au fait, la principale raison pour laquelle j'utilise ces fonctions est d'utiliser des tableaux sous forme d'ensembles, c'est-à-dire sans éléments en double. Y a-t-il autre chose que je pourrais utiliser?

Wookai
la source
3
que signifie la notation _,?
Martin
24
C'est simplement une variable "garbage" 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 ) d'utiliser cette _variable pour stocker des choses dont vous n'avez pas besoin.
Wookai
J'ai également vu la convention de nommer les variables "garbage" _utilisées en Python et JavaScript.
iono

Réponses:

115

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 y a un exemple plus complet ici .

interjay
la source
13
Un utilisateur anonyme a proposé le correctif suivant à votre code: Si la valeur de l'ensemble avec la clé spécifiée est FALSE, la fonction setContains () renvoie un faux 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.
oers
Peut-être aussifunction keysOfSet(set) local ret={} for k,_ in pairs(set) do ret[#ret+1]=k end return ret end
Jesse Chisholm
24

Compte tenu de votre représentation, votre fonction est aussi efficace que possible. Bien sûr, comme l'ont noté d'autres (et comme cela est pratiqué dans des langues plus anciennes que le Lua), la solution à votre vrai problème est de changer de représentation. Lorsque vous avez des tables et que vous voulez des ensembles, vous transformez les tables en ensembles en utilisant l'élément set comme clé et truecomme valeur. +1 à l'interjay.

Norman Ramsey
la source
2

Je ne peux pas penser à une autre façon de comparer les valeurs, mais si vous utilisez l'élément de l'ensemble comme clé, vous pouvez définir la valeur sur autre chose que nil. Ensuite, vous obtenez des recherches rapides sans avoir à rechercher dans toute la table.

Joël
la source
2

Je sais que c'est un ancien post, mais je voulais ajouter quelque chose pour la postérité. Le moyen simple de gérer le problème que vous rencontrez est de créer une autre table, de valeur à clé.

c'est à dire. vous avez 2 tables qui ont la même valeur, l'une pointant dans une direction, l'autre pointant 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 à parcourir chaque valeur de l'autre table.

S'il s'avère que vous ne pouvez pas réellement utiliser l'élément `` élément '' comme clé, car ce n'est pas une chaîne par exemple, ajoutez une somme de contrôle ou tostring dessus par exemple, puis utilisez-la comme clé.

Pourquoi veux-tu faire cela? Si vos tables sont très volumineuses, le temps nécessaire pour parcourir chaque élément sera important, vous empêchant de le faire très souvent. La surcharge de mémoire supplémentaire sera relativement faible, car elle stockera 2 pointeurs vers le même objet, plutôt que 2 copies du même objet. Si vos tables sont très petites, cela importera beaucoup moins, en fait, il peut même être plus rapide d'itérer que d'avoir une autre recherche de carte.

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

James
la source
Une bonne explication, mais qui n'ajoute vraiment rien à la discussion. Cela aurait probablement été une meilleure idée de modifier la réponse d'Interjay.
bcdan
1
De plus, '.key' doit être remplacé par '[key]' partout dans ce code (même chose avec 'value')
Njol