Come verificare se una tabella contiene un elemento in Lua?


97

Esiste un metodo per verificare se una tabella contiene un valore? Ho la mia (ingenua) funzione, ma mi chiedevo se esiste qualcosa di "ufficiale" per questo? O qualcosa di più efficiente ...

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

A proposito, il motivo principale per cui utilizzo queste funzioni è utilizzare le tabelle come insiemi, cioè senza elementi duplicati. C'è qualcos'altro che potrei usare?


3
cosa significa la notazione _,?
Martin,

24
È semplicemente una variabile "spazzatura" denominata _. pairs()restituisce key, value, ma in questo esempio ho solo bisogno del valore. È una specie di convenzione (adottata nel libro "Programming in Lua" lua.org/pil/index.html ) usare questa _variabile per memorizzare cose di cui non hai bisogno.
Wookai

Ho visto anche la convenzione di denominare variabili "spazzatura" _usate in Python e JavaScript.
iono

Risposte:


115

Puoi mettere i valori come chiavi della tabella. Per esempio:

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

C'è un esempio più completo qui .


13
Un utente anonimo ha proposto la seguente correzione al codice: Se il valore nel set con la chiave specificata è FALSE, la funzione setContains () restituisce un falso sebbene nella tabella sia presente un elemento con la chiave specificata. la riga "return set [key] ~ = nil" corregge quell'errore.
oers

Forse anchefunction keysOfSet(set) local ret={} for k,_ in pairs(set) do ret[#ret+1]=k end return ret end
Jesse Chisholm

24

Data la tua rappresentazione, la tua funzione è il più efficiente possibile. Naturalmente, come notato da altri (e come praticato in lingue più vecchie di Lua), la soluzione al tuo vero problema è cambiare la rappresentazione. Quando si hanno tabelle e si vogliono insiemi, si trasformano le tabelle in insiemi utilizzando l'elemento set come chiave e truecome valore. +1 a interjay.


2

Non riesco a pensare a un altro modo per confrontare i valori, ma se usi l'elemento dell'insieme come chiave, puoi impostare il valore su qualcosa di diverso da zero. Quindi ottieni ricerche veloci senza dover cercare l'intera tabella.


2

So che questo è un vecchio post, ma volevo aggiungere qualcosa per i posteri. Il modo semplice per gestire il problema che hai è creare un'altra tabella, di valore in chiave.

cioè. hai 2 tabelle che hanno lo stesso valore, una che punta in una direzione, una che punta nell'altra.

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

Puoi quindi interrogare la nuova tabella per vedere se ha la chiave "elemento". Ciò impedisce la necessità di iterare attraverso ogni valore dell'altra tabella.

Se risulta che non puoi effettivamente usare l '"elemento" come chiave, perché ad esempio non è una stringa, aggiungi un checksum o tostringsu di esso ad esempio, e poi usalo come chiave.

Perchè vuoi fare questo? Se le tue tabelle sono molto grandi, la quantità di tempo per scorrere ogni elemento sarà significativa, impedendoti di farlo molto spesso. Il sovraccarico di memoria aggiuntivo sarà relativamente piccolo, poiché memorizzerà 2 puntatori allo stesso oggetto, anziché 2 copie dello stesso oggetto. Se le tue tabelle sono molto piccole, allora importerà molto meno, infatti potrebbe essere anche più veloce iterare che avere un'altra ricerca sulla mappa.

La formulazione della domanda, tuttavia, suggerisce fortemente che hai un gran numero di elementi da affrontare.


Una buona spiegazione, ma in realtà non aggiunge nulla alla discussione. Probabilmente sarebbe stata un'idea migliore modificare la risposta di interjay.
bcdan

1
Inoltre, ".key" dovrebbe essere sostituito con "[key]" ovunque in questo codice (lo stesso di "value")
Njol
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.