¿La forma más eficiente de determinar si una tabla Lua está vacía (no contiene entradas)?


120

¿Cuál es la forma más eficiente de determinar si una tabla está vacía (es decir, actualmente no contiene ni valores de estilo de matriz ni valores de estilo dict)?

Actualmente, estoy usando next():

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

¿Existe una forma más eficiente?

Nota: El #operador no es suficiente aquí, ya que solo opera en los valores de estilo de matriz en la tabla; por lo tanto, #{test=2}es indistinguible de #{}porque ambos devuelven 0. También tenga en cuenta que verificar si la variable de la tabla es nilno es suficiente porque no estoy buscando valores nulos, sino tablas con 0 entradas (es decir {}).

Respuestas:


151

Tu código es eficiente pero incorrecto. (Considérelo {[false]=0}). El código correcto es

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

Para obtener la máxima eficiencia, querrá vincularse nexta una variable local, por ejemplo,

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

1
Buen punto sobre la corrección técnica; en los casos particulares en los que he estado utilizando el código original, falseno sería una clave esperada, por lo que if notfuncionó bien, pero probablemente me acostumbré a comparar nilen el futuro, solo como un buen hábito. Y sí, he estado vinculando funciones de utilidad comunes a vars locales para mejorar la velocidad. Sin embargo, gracias por la entrada.
Ámbar

1
Me resulta difícil estar de acuerdo con lo incorrecto cuando el código funciona según lo previsto
RD Alkire

4
¿Por qué ganamos velocidad al hacerlo local next?
Moberg

2
@Moberg Esto se debe a cómo LUA maneja su espacio de nombres. La versión muy simplificada es que primero subirá las tablas locales, por lo que si hay un local nexten el bloque actual, lo usará, luego subirá al siguiente bloque y repetirá. Una vez fuera de los locales, solo usará el espacio de nombres global. Esta es una versión simplificada, pero al final, definitivamente significa la diferencia en lo que respecta a la velocidad del programa.
ATaco

@Moberg, la versión menos simplificada, en el contexto de lua 5.2 y 5.3, es que los no locales son upvals o búsquedas _ENV. Un upval tiene que pasar por una capa adicional de direccionamiento indirecto, mientras que una búsqueda _ENV es una búsqueda de tabla. Considerando que un local es un registro en el VM
Demur Rumed

1

Una posibilidad sería contar el número de elementos, utilizando la clave de metatabla "newindex". Cuando asigne algo que no nil, incremente el contador (el contador también podría vivir en la metatabla) y cuando asigne nil, decremente el contador.

Probar una tabla vacía sería probar el contador con 0.

Aquí hay un puntero a la documentación de metatabla

Sin embargo, me gusta tu solución y, sinceramente, no puedo asumir que mi solución sea más rápida en general.


5
La pregunta original no se trata de contar solo las entradas de "matriz".
lhf

3
La sugerencia de 0x6 no es específica de las entradas de estilo de matriz (newindex funciona tanto para índices numéricos como no numéricos). Sin embargo, el problema principal sería detectar cuándo nilse asigna, ya que __newindex no se activa si la clave ya existe en la tabla.
Ámbar

3
Para que este truco funcione, la metatabla tendría que implementar tanto __indexy __newindex, almacenando los datos reales en una tabla sombra y manteniendo la tabla real vacía para que __indexse invoque. Pensando en voz alta, sospecho que el costo elevado de cada búsqueda no puede valer la pena.
RBerteig

0

Probablemente esto es lo que querías:

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

Salida:

true
false
true

11
next()es más eficiente (y más conciso) que recorrer en bucle pairs().
Ámbar

8
De hecho, hacer un bucle pairs() es básicamente usar la next()técnica, pero con más gastos generales.
dubiousjim

7
Además, tableno se recomienda escribir en la biblioteca estándar .
Ti Strga

-1

mejor evitar la evaluación de __eq si está sobrecargado.

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

o

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

1
Soy un novato de Lua que intenta entender por qué esta respuesta fue rechazada. Supongo que es porque en Lua, "si dos objetos tienen diferentes metamétodos, la operación de igualdad da como resultado falso, sin siquiera llamar a ningún metamétodo". (La cita está al final de esta página de Programación en Lua en lua.org ). ¿Elimina eso la necesidad de evitar la sobrecarga de __eq por cero?
SansWit

-1

prueba serpiente, trabaja para mi

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

-2

Qué tal esto ?

if endmyTable[1] == nil then
  -- myTable is empty
end

1
Esto no funcionará en una tabla que
tenga

-3

Sé que esto es antiguo y podría malinterpretarlo de alguna manera, pero si solo desea que la mesa esté vacía, es decir, a menos que solo esté verificando si lo está y en realidad no quiere o necesita que esté vacía, puede borrarlo simplemente recreándolo, a menos que me equivoque. esto se puede hacer con la siguiente sintaxis.

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

4
Ésa no es la cuestión.
Yu Hao

-6

Intente usar #. Devuelve todas las instancias que están en una tabla. Si no hay instancias en una tabla, devuelve0

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

1
El autor de la pregunta dice que #eso no será suficiente aquí, y explica por qué; ¿Podría explicar por qué esto evita esas razones?
editado el

bueno ... no lo sé Soy nuevo en esto, así que la única forma que sé es usando #
arthurgps2
Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.