Le moyen le plus efficace de déterminer si une table Lua est vide (ne contient aucune entrée)?


120

Quelle est la manière la plus efficace de déterminer si une table est vide (c'est-à-dire qu'elle ne contient actuellement ni valeurs de style tableau ni valeurs de style dict)?

Actuellement, j'utilise next():

if not next(myTable) then
    -- Table is empty
end

Existe-t-il un moyen plus efficace?

Remarque: L' #opérateur ne suffit pas ici, car il n'opère que sur les valeurs de style tableau dans la table - il #{test=2}est donc impossible de distinguer #{}car les deux renvoient 0. Notez également que vérifier si la variable de table est nilne suffit pas car je ne recherche pas valeurs nulles, mais plutôt des tables avec 0 entrées (ie {}).

Réponses:


151

Votre code est efficace mais faux. (Considérez {[false]=0}.) Le code correct est

if next(myTable) == nil then
   -- myTable is empty
end

Pour une efficacité maximale, vous voudrez vous lier nextà une variable locale, par exemple,

...
local next = next 
...
... if next(...) ...

1
Bon point sur l'exactitude technique; dans les cas particuliers où j'ai utilisé le code original, falsece ne serait pas une clé attendue, donc cela if notfonctionnait bien, mais je prendrai probablement l'habitude de comparer à la nilplace à l'avenir, tout comme une bonne habitude. Et oui, j'ai lié les fonctions utilitaires communes aux variables locales pour la vitesse. Merci pour votre contribution.
Ambre

1
J'ai du mal à être d'accord avec l'erreur lorsque le code fonctionne comme prévu
RD Alkire

4
Pourquoi gagner de la vitesse en faisant local next?
Moberg

2
@Moberg Cela est dû à la façon dont LUA gère son espace de noms. La version très simplifiée, c'est qu'elle grimpera d'abord dans les tables locales, donc s'il y a un local nextdans le bloc actuel, il l'utilisera, puis grimpera au bloc suivant et répétera. Une fois hors des locaux, il n'utilisera alors que l'espace de noms global. Il s'agit d'une version simplifiée de celui-ci, mais en fin de compte, cela signifie définitivement la différence en ce qui concerne la vitesse du programme.
ATaco

@Moberg, la version la moins stupide, dans le contexte de lua 5.2 et 5.3, est que les non locaux sont soit des valeurs ascendantes, soit des recherches _ENV. Un upval doit passer par une couche supplémentaire d'indirection, alors qu'une recherche _ENV est une recherche de table. Alors qu'un local est un registre dans la VM
Demur Rumed

1

Une possibilité serait de compter le nombre d'éléments, en utilisant la clé métatable "newindex". Lors de l'affectation de quelque chose qui ne l'est pas nil, incrémentez le compteur (le compteur peut également vivre dans la métatable) et lors de l'assignation nil, décrémentez le compteur.

Tester une table vide serait de tester le compteur avec 0.

Voici un pointeur vers la documentation métatable

Cependant, j'aime votre solution et je ne peux honnêtement pas supposer que ma solution est globalement plus rapide.


5
La question initiale n'est pas de ne compter que les entrées "tableau".
lhf

3
La suggestion de 0x6 n'est pas spécifique aux entrées de style tableau (newindex fonctionne pour les indices numériques et non numériques). Cependant, le principal problème serait de détecter quand nilest attribué, puisque __newindex ne se déclenche pas si la clé existe déjà dans la table.
Ambre

3
Pour que cette astuce fonctionne, le métatable devrait implémenter à la fois __indexet __newindex, stocker les données réelles dans une table fantôme et garder la table réelle vide pour qu'elle __indexsoit invoquée du tout. En réfléchissant à haute voix, je soupçonne que le coût élevé de chaque recherche ne peut en valoir la peine.
RBerteig

0

C'est probablement ce que vous vouliez:

function table.empty (self)
    for _, _ in pairs(self) do
        return false
    end
    return true
end

a = { }
print(table.empty(a))
a["hi"] = 2
print(table.empty(a))
a["hi"] = nil
print(table.empty(a))

Production:

true
false
true

11
next()est plus efficace (et plus concis) que le bouclage pairs().
Ambre

8
En fait, le bouclage pairs() consiste essentiellement à utiliser la next()technique, mais avec plus de surcharge.
dubiousjim

7
De plus, l'écriture dans la tablebibliothèque standard n'est pas recommandée.
Ti Strga

-1

mieux vaut éviter l'évaluation de __eq en cas de surcharge.

if rawequal(next(myTable), nil) then
   -- myTable is empty
end

ou

if type(next(myTable)) == "nil" then
   -- myTable is empty
end

1
Je suis un Lua noob essayant de comprendre pourquoi cette réponse a été rejetée. Je suppose que c'est parce que dans Lua, "si deux objets ont des métaméthodes différentes, l'opération d'égalité aboutit à false, sans même appeler aucune métaméthode". (La citation est au bas de cette page de Programming in Lua sur lua.org ). Cela supprime-t-il le besoin d'éviter la surcharge de __eq pour nil?
SansWit

-1

essaie le serpent, travaille pour moi

serpent = require 'serpent'

function vtext(value)
  return serpent.block(value, {comment=false})
end

myTable = {}

if type(myTable) == 'table' and vtext(myTable) == '{}' then
   -- myTable is empty
end


-3

Je sais que c'est vieux, et je pourrais me mal comprendre d'une manière ou d'une autre, mais si vous voulez juste que la table soit vide, c'est-à-dire à moins que vous ne vérifiiez simplement si elle l'est et que vous ne voulez pas ou n'avez pas besoin qu'elle soit vide, vous pouvez l'effacer en le recréant simplement, sauf erreur de ma part. cela peut être fait avec la syntaxe ci-dessous.

yourtablename = {} -- this seems to work for me when I need to clear a table.

4
Ce n'est pas la question.
Yu Hao

-6

Essayez d'utiliser #. Il renvoie toutes les instances présentes dans une table. S'il n'y a pas d'instances dans une table, il renvoie0

if #myTable==0 then
print('There is no instance in this table')
end

1
Le demandeur dit que #cela ne suffira pas ici, et en donne les raisons; pourriez-vous expliquer pourquoi cela contourne ces raisons?
Ameed le

eh bien ... je ne sais pas, je suis nouveau dans ce domaine, donc la seule façon dont je sais est d'utiliser #
arthurgps2
En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.