88 votes

Comment supprimer une entrée de table lua par sa clé ?

J'ai une table lua que j'utilise comme un hashmap, c'est-à-dire avec des clés de type chaîne :

local map = { foo = 1, bar = 2 }

Je voudrais "pop" un élément de cette table identifié par sa clé. Il existe un table.remove() mais elle ne prend que l'index de l'élément à supprimer (c'est-à-dire un nombre) et non une clé générique. J'aimerais pouvoir faire table.remove(map, 'foo') et voici comment je l'ai mis en œuvre :

function table.removekey(table, key)
    local element = table[key]
    table[key] = nil
    return element
end

Y a-t-il une meilleure façon de procéder ?

77voto

Amber Points 159296

Non, en mettant la valeur de la clé à nil est la manière acceptée de supprimer un élément dans la partie hashmap d'une table. Ce que vous faites est standard. Cependant, je vous recommande de ne pas surcharger la fonction table.remove() - pour la partie tableau d'un tableau, la fonctionnalité par défaut table.remove() inclut la renumérotation des indices, ce que votre surcharge ne ferait pas. Si vous souhaitez ajouter votre fonction à la classe table alors je l'appellerais probablement quelque chose comme table.removekey() ou autre.

8voto

cubuspl42 Points 1293

TLDR

(parce que vous n'essayez que de supprimer une chose d'une carte, c'est pas si difficile que ça)

Mise en place d'une touche nil (par exemple t[k] = nil ) n'est pas seulement acceptée et standard, mais c'est aussi la norme de l seulement une façon de retirer l'entrée du "contenu" de la table en général. Et c'est logique. De plus, la partie tableau et la partie hashmap sont détails de mise en œuvre et n'auraient jamais dû être mentionnés dans cette Q/A. .

Comprendre les tables de Lua

(et pourquoi on ne peut pas supprimer un infini)

Les tables Lua n'ont pas littéralement de concept de "suppression d'une entrée d'une table" et n'ont pratiquement pas de concept d'"insertion d'une entrée dans une table". Ceci est différent de beaucoup d'autres structures de données de différents langages de programmation.

En Lua, les tables modélisent une structure associative parfaite de taille infinie.

Les tables en Lua sont intrinsèquement mutables et il n'y a qu'une seule façon fondamentale de construire une nouvelle table : en utilisant la fonction {} l'expression. La construction d'un tableau avec un contenu initial (par ex. t = {10, 20, ["foo"] = 123, 30} ou autre) est en fait un sucre syntaxique équivaut à construire d'abord un nouveau tableau (par ex. t = {} }, puis en définissant les entrées "initiales" une à une (par ex. t[1] = 10 , t[2] = 20 , t["foo"] = 123 , t[3] = 30 ) . Les détails du fonctionnement du désucrage n'aident pas à comprendre le sujet abordé, c'est pourquoi j'éviterai d'utiliser le tableau de construction du sucre dans cette réponse.

En Lua, un tableau fraîchement construit associe d'abord toutes les valeurs possibles à nil . Cela signifie que pour un tableau t = {} , t[2] évaluera à nil , t[100] évaluera à nil , t["foo"] évaluera à nil , t[{}] évaluera à nil , etc.

Après la construction, vous pouvez modifier le tableau en procédant comme suit réglage une valeur à une certaine clé. Cette clé sera alors associée à cette valeur. Par exemple, après avoir défini t["foo"] = "bar" , la clé "foo" sera désormais associé à la valeur "bar" . En conséquence, t["foo"] sera désormais évaluée à "bar" .

Paramètres nil à une certaine touche associera cette touche à nil . Par exemple, après avoir défini t["foo"] = nil , "foo" sera (à nouveau) associé à nil . En conséquence, t["foo"] sera (à nouveau) évaluée à nil .

Si n'importe quelle clé peut être associée à nil (et initialement toutes les clés possibles le sont), ces entrées (paires clé/valeur) ne sont pas prises en compte. une partie de la table (c'est-à-dire qu'ils ne sont pas considérés comme faisant partie du tableau contenu ).

Fonctions pairs y ipairs (et plusieurs autres) opèrent sur le contenu du tableau, c'est-à-dire les associations dont la valeur n'est pas nil . Le nombre de ces associations est toujours fini.

Compte tenu de ce qui précède, l'association d'une clé avec nil fera probablement tout ce à quoi vous pouvez vous attendre lorsque vous dites "supprimer une entrée d'un tableau", parce que t[k] évaluera à nil (comme il l'a fait après avoir construit le tableau) et des fonctions comme pairs y ipairs ignorera ces entrées, car les entrées (associations) ayant une valeur nil ne sont pas considérés comme "faisant partie de la table".

Séquences

(si les tableaux n'étaient pas déjà compliqués)

Dans cette réponse, je parle des tableaux en général c'est-à-dire sans aucune hypothèse sur leurs clés. En Lua, les tables ayant un ensemble particulier de clés peuvent être appelées des séquence et vous pouvez utiliser table.remove pour supprimer une clé entière de cette table. Mais, premièrement, cette fonction est effectivement indéfinie pour les non-séquences (c'est-à-dire les tableaux en général) et, deuxièmement, il n'y a aucune raison de supposer que c'est plus qu'un util, c'est-à-dire quelque chose qui pourrait être directement implémenté en Lua en utilisant des opérations primitives.

La question de savoir quelles tables sont ou ne sont pas une séquence est un autre sujet épineux et je n'entrerai pas dans les détails ici.

Référencement de la référence

(Je n'ai pas inventé tout cela)

Tout ce qui précède est basé sur le document officiel de la Commission européenne. manuel de référence linguistique . Les parties intéressantes sont surtout des chapitres 2.1 - Valeurs et types ...

Les tableaux peuvent être hétérogènes, c'est-à-dire qu'ils peuvent contenir des valeurs de tous types (sauf nil). Toute clé dont la valeur est nulle n'est pas considérée comme faisant partie de la table. Inversement, toute clé qui ne fait pas partie d'une table a une valeur associée nulle.

Cette partie n'est pas parfaitement formulée. Tout d'abord, la phrase "les tableaux peuvent être hétérogènes" prête à confusion. C'est la seule utilisation de ce terme dans la référence et la partie "peuvent être" ne permet pas de savoir si "être hétérogènes" est un terme qui peut être utilisé pour désigner des tableaux. possible d'un tableau, ou si les tableaux de ce dernier sont défini de cette manière. La deuxième phrase rend la première explication plus raisonnable, car si "toute clé de valeur nulle n'est pas considérée comme faisant partie de la table", cela signifie que "une clé de valeur nulle" n'est pas une contradiction. De plus, la spécification de l'élément rawset qui donne (indirectement) la sémantique à la fonction t[k] = v dans la syntaxe 6.1 - Fonctions de base chapitre dit...

Fixe la valeur réelle de table[index] à value, sans invoquer de métaméthode. table doit être une table, index toute valeur différente de nil et NaN, et value toute valeur Lua.

En tant que nil ne sont pas des cas particuliers ici, ce qui signifie que vous pouvez peut fixer t[k] a nil . La seule façon de comprendre cela est d'accepter qu'à partir de maintenant, cette clé sera "une clé avec une valeur nulle", et par conséquent "ne sera pas considérée comme faisant partie de la table" ( pairs l'ignorera, etc.), et comme "toute clé qui ne fait pas partie d'une table a une valeur associée nulle", t[k] évaluera à nil .

L'ensemble de la référence ne mentionne pas non plus la "suppression" d'une clé ou d'une entrée dans les tables à un autre endroit.

Une autre perspective sur les tableaux

(si vous détestez les infinis)

Si je trouve personnellement la perspective de la référence élégante, je comprends aussi que le fait qu'elle soit différente d'autres modèles populaires puisse la rendre plus difficile à raisonner.

Je pense que la perspective suivante est effectivement équivalente à la précédente.

On peut penser que...

  • {} renvoie un vide table.
  • t[k] s'évalue à v si t contient clé k y nil autrement
  • Paramètres t[k] = v inserts une nouvelle entrée ( k , v ) à la table si elle ne contient pas de clé k , mises à jour cette inscription si t contient déjà la clé k et enfin, en tant que cas particulier , supprime l'entrée pour la clé k si v es nil
  • Les contenu de la table (c'est-à-dire ce qui est considéré comme "une partie de la table") est l'ensemble de toutes les entrées de la table

Dans ce modèle, les tableaux ne sont pas capables de "contenir" nil valeurs.

Esto es pas La définition de la langue de référence n'est pas la même, mais pour autant que je sache, ce modèle est équivalent sur le plan de l'observation.

Ne pas parler des détails de la mise en œuvre

(sauf si vous êtes sûr que c'est ce que vous voulez dire)

La partie dite "hashmap" du tableau (qui complète la partie dite "tableau" du tableau) est la suivante détails de la mise en œuvre et en parler, à moins de discuter des performances ou de l'explication de comportements spécifiques non définis ou définis par l'implémentation, est à mon avis source de confusion dans le meilleur des cas et tout simplement erroné dans le pire.

Par exemple, dans un tableau construit comme suit... t = {} , t[1] = 10 , t[2] = 20 , t[3] = 30 la partie tableau sera (probablement !) [10, 20, 30] et la mise en place t[2] = nil supprimera l'entrée ( 2 , 20 ) "à partir de la partie tableau", éventuellement en le redimensionnant ou en le déplaçant. 3 -> 30 à la partie hashmap. Je n'en suis pas vraiment sûr. Je dis cela pour prouver que discuter des détails de l'implémentation n'est pas ce que nous voulons faire ici.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X