Come verificare se una tabella contiene un elemento in Lua?
Domanda
Esiste un metodo per il controllo se una tabella contiene un valore? Io ho la mia propria funzione (naive), ma mi chiedevo se qualcosa di "ufficiale" esiste 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
Tra l'altro, il motivo principale che sto utilizzando questa funzione è quello di utilizzare le tabelle come set, cioè senza elementi duplicati. C'è qualcos'altro che potrei usare?
Soluzione
È possibile inserire i valori come chiavi della tabella. Ad 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ù pieno-caratterizzato qui .
Altri suggerimenti
Data la sua rappresentazione, la funzione è efficiente come si può fare. Naturalmente, come notato da altri (e praticata in lingue più vecchio di Lua), la soluzione al vostro problema vero è quello di cambiare la rappresentazione. Quando si dispone di tabelle e si desidera set, è trasformare le tabelle in gruppi utilizzando l'elemento impostato come chiave e true
come valore. +1 a interjay.
Non riesco a pensare ad un altro modo per confrontare i valori, ma se si utilizza l'elemento del set come il tasto, è possibile impostare il valore a qualcosa di diverso da zero. Poi si arriva ricerche veloci, senza dover cercare l'intera tabella.
So che questo è un vecchio post, ma ho voluto aggiungere qualcosa per i posteri. Il modo più semplice di gestire il problema che si ha è di fare un altro tavolo, di valore per chiave.
es. hai 2 tabelle che hanno lo stesso valore, uno che punta in una direzione, uno indicando l'altro.
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
È quindi possibile interrogare la nuova tabella per vedere se ha il tasto 'elemento'. Questo evita la necessità di scorrere ogni valore della tabella.
Se si scopre che non si può effettivamente utilizzare il 'elemento' come una chiave, perché non è una stringa, ad esempio, quindi aggiungere un checksum o tostring
su di esso per esempio, e quindi utilizzare tale come chiave.
Perché vuoi fare questo? Se le tabelle sono molto grandi, la quantità di tempo per scorrere attraverso ogni elemento sarà significativo, si impedisce di fare molto spesso. L'overhead di memoria aggiuntiva sarà relativamente piccola, come verrà memorizza 2 puntatori allo stesso oggetto, anziché 2 copie dello stesso oggetto. Se le tabelle sono molto piccole, poi si importa molto meno, infatti può anche essere più veloce per iterare che avere un'altra mappa di ricerca.
La formulazione della domanda suggerisce tuttavia vivamente di avere un gran numero di elementi da affrontare.