Como verificar se uma tabela contém um elemento na Lua?
Pergunta
Existe um método para verificar se uma tabela contém um valor? Eu tenho minha própria função (ingênua), mas queria saber se algo "oficial" existe para isso? Ou algo mais eficiente ...
function table.contains(table, element)
for _, value in pairs(table) do
if value == element then
return true
end
end
return false
end
A propósito, a principal razão pela qual estou usando essas funções é usar tabelas como conjuntos, ou seja, sem elementos duplicados. Há algo mais que eu poderia usar?
Solução
Você pode colocar os valores como as chaves da tabela. Por exemplo:
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
Há um exemplo mais totalmente completo aqui.
Outras dicas
Dada sua representação, Sua função é tão eficiente quanto pode ser feita. Obviamente, como observado por outros (e como praticado em idiomas mais antigos que Lua), a solução para o seu verdadeiro problema é mudar a representação. Quando você tem mesas e deseja conjuntos, você transforma as mesas em conjuntos usando o elemento definido como a chave e true
como o valor. +1 para interjay.
Não consigo pensar em outra maneira de comparar valores, mas se você usar o elemento do conjunto como a chave, poderá definir o valor para qualquer coisa que não seja nulo. Então você obtém pesquisas rápidas sem precisar pesquisar a tabela inteira.
Eu sei que este é um post antigo, mas eu queria adicionar algo para a posteridade. A maneira simples de lidar com o problema que você tem é fazer outra tabela, de valor para a chave.
ou seja. Você tem duas tabelas com o mesmo valor, uma apontando uma direção, uma apontando a outra.
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
Você pode consultar a nova tabela para ver se ela possui a chave 'elemento'. Isso impede a necessidade de iterar em todos os valores da outra tabela.
Se você realmente não pode usar o 'elemento' como uma chave, porque não é uma string, por exemplo, adicione uma soma de verificação ou tostring
Por exemplo, e depois use isso como a chave.
Por que você quer fazer isso? Se suas mesas forem muito grandes, a quantidade de tempo para iterar em todos os elementos será significativa, impedindo que você o faça com muita frequência. A sobrecarga de memória adicional será relativamente pequena, pois armazenará 2 ponteiros no mesmo objeto, em vez de 2 cópias do mesmo objeto. Se suas mesas forem muito pequenas, isso importará muito menos, de fato, pode até ser mais rápido para iterar do que ter outra pesquisa de mapa.
A redação da questão, no entanto, sugere fortemente que você tem um grande número de itens para lidar.