¿Cómo comprobar si una tabla contiene un elemento en Lua?

97

¿Existe algún método para verificar si una tabla contiene un valor? Tengo mi propia función (ingenua), pero me preguntaba si existe algo "oficial" para eso. O algo más eficiente ...

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

Por cierto, la razón principal por la que estoy usando estas funciones es para usar tablas como conjuntos, es decir, sin elementos duplicados. ¿Hay algo más que pueda usar?

Wookai
fuente
3
¿Qué significa la notación _?
Martin
24
Es simplemente una variable "basura" llamada _. pairs()devuelve key, value, pero en este ejemplo solo necesito el valor. Es una especie de convención (adoptada en el libro "Programación en Lua" lua.org/pil/index.html ) utilizar esta _variable para almacenar cosas que no necesitas.
Wookai
También he visto la convención de nombrar variables "basura" _utilizadas en Python y JavaScript.
iono

Respuestas:

115

Puede poner los valores como claves de la tabla. Por ejemplo:

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

Hay un ejemplo más plenamente las funciones aquí .

interjay
fuente
13
Un usuario anónimo propuso la siguiente solución a su código: Si el valor en el conjunto con la clave especificada es FALSO, entonces la función setContains () devuelve un falso aunque hay un elemento en la tabla con la clave especificada. la línea "return set [key] ~ = nil" corrige ese error.
ofrece
Quizás tambiénfunction keysOfSet(set) local ret={} for k,_ in pairs(set) do ret[#ret+1]=k end return ret end
Jesse Chisholm
24

Dada su representación, su función es lo más eficiente posible. Por supuesto, como han señalado otros (y como se practica en idiomas más antiguos que Lua), la solución a su problema real es cambiar la representación. Cuando tenga tablas y desee conjuntos, convierta las tablas en conjuntos utilizando el elemento conjunto como clave y truecomo valor. +1 para interjay.

Norman Ramsey
fuente
2

No puedo pensar en otra forma de comparar valores, pero si usa el elemento del conjunto como clave, puede establecer el valor en cualquier otro valor que no sea nil. Luego, obtiene búsquedas rápidas sin tener que buscar en toda la tabla.

Joel
fuente
2

Sé que esta es una publicación antigua, pero quería agregar algo para la posteridad. La forma sencilla de manejar el problema que tiene es hacer otra tabla, de valor a clave.

es decir. tienes 2 tablas que tienen el mismo valor, una apuntando en una dirección y otra apuntando a la otra.

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

A continuación, puede consultar la nueva tabla para ver si tiene el 'elemento' clave. Esto evita la necesidad de iterar a través de cada valor de la otra tabla.

Si resulta que en realidad no puede usar el 'elemento' como clave, porque no es una cadena, por ejemplo, agregue una suma de verificación o tostringen él, por ejemplo, y luego utilícelo como clave.

¿Por qué quieres hacer esto? Si sus tablas son muy grandes, la cantidad de tiempo para iterar a través de cada elemento será significativa, lo que le impedirá hacerlo con mucha frecuencia. La sobrecarga de memoria adicional será relativamente pequeña, ya que almacenará 2 punteros al mismo objeto, en lugar de 2 copias del mismo objeto. Si sus tablas son muy pequeñas, entonces importará mucho menos, de hecho, puede ser incluso más rápido iterar que tener otra búsqueda de mapa.

Sin embargo, la redacción de la pregunta sugiere fuertemente que tiene una gran cantidad de temas de los que ocuparse.

James
fuente
Una buena explicación, pero en realidad no aporta nada a la discusión. Probablemente hubiera sido una mejor idea editar la respuesta de Interjay.
bcdan
1
Además, '.key' debe reemplazarse con '[key]' en todas partes de este código (lo mismo con 'value')
Njol