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?

Foi útil?

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.

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top