如何通过键删除lua表条目?

发布于 2024-08-11 05:43:21 字数 390 浏览 2 评论 0原文

我有一个用作散列图的 lua 表,即带有字符串键:

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

我想“弹出”该表中由其键标识的元素。有一个 table.remove() 方法,但它只需要要删除的元素的索引(即数字)而不是通用键。我希望能够执行 table.remove(map, 'foo') 这就是我的实现方式:

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

有更好的方法吗?

I have a lua table that I use as a hashmap, ie with string keys :

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

I would like to "pop" an element of this table identified by its key. There is a table.remove() method, but it only takes the index of the element to remove (ie a number) and not a generic key. I would like to be able to do table.remove(map, 'foo') and here is how I implemented it :

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

Is there a better way to do that ?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

︶ ̄淡然 2024-08-18 05:43:21

不,将键的值设置为nil 是删除表的哈希映射部分中的项目的可接受方法。你正在做的事情是标准的。但是,我建议不要覆盖 table.remove() - 对于表的数组部分,默认的 table.remove() 功能包括对索引重新编号,而您的覆盖不会执行此操作。如果您确实想将函数添加到 table 函数集中,那么我可能会将其命名为 table.removekey() 或类似的名称。

No, setting the key's value to nil is the accepted way of removing an item in the hashmap portion of a table. What you're doing is standard. However, I'd recommend not overriding table.remove() - for the array portion of a table, the default table.remove() functionality includes renumbering the indices, which your override would not do. If you do want to add your function to the table function set, then I'd probably name it something like table.removekey() or some such.

べ繥欢鉨o。 2024-08-18 05:43:21

TLDR

(因为你只是想从地图上删除一个东西,这有多难)

将键设置为 nil (例如 t[k ] = nil) 不仅被接受和标准,而且它是一般从表的“内容”中删除条目的唯一方法。这是有道理的。此外,数组部分和哈希图部分是实现细节,不应该在本问答中提及

理解 Lua 的表

(以及为什么不能从无限中删除)

Lua 表实际上没有“从表中删除条目”的概念,也几乎没有“插入条目”的概念到一张桌子”。这与不同编程语言的许多其他数据结构不同。

在Lua中,表模拟了无限大小的完美关联结构。

Lua 中的表本质上是可变的,构建新表的基本方法只有一种:使用 {} 表达式。使用初始内容(例如 t = {10, 20, ["foo"] = 123, 30} 或类似内容)构建一个表格实际上是一个 语法糖 相当于首先构造一个新表(例如 t = {}} 和然后一一设置“初始”条目(例如t[1] = 10t[2] = 20t["foo"] = 123, t[3] = 30) 去糖工作原理的细节无助于理解所讨论的问题,因此我将避免使用表构造糖。 。

在 Lua 中,新构建的表最初将所有可能的值与 nil 关联起来,这意味着对于表 t = {}t[2] ] 将计算为 nilt[100] 将计算为 nilt["foo"]< /code> 将计算为 nilt[{}] 将计算为 nil 等。

构建后,您可以通过以下方式更改表设置某个键的值。然后该键现在将与该值关联。例如,设置 t["foo"] = "bar" 后,键 "foo" 现在将与值 "bar" 关联代码>.因此,t["foo"] 现在将计算为 "bar"

在某个键上设置 nil 会将该键与 nil 关联起来。例如,设置 t["foo"] = nil 后,"foo" 将(再次)与 nil 关联。因此,t["foo"] 将(再次)计算为 nil

虽然任何键都可以与 nil 关联(并且最初所有可能的键都是),但此类条目(键/值对)不被视为表的一部分(即不被视为表格内容的一部分)。

函数pairsipairs(以及其他多个)对表的内容进行操作,即值不nil 的关联。此类关联的数量始终是有限的。

考虑到上面所说的一切,将键与 nil 相关联可能会完成您在说“从表中删除条目”时所期望的一切,因为 t[k] 会评估为nil(就像构建表后所做的那样),并且诸如pairsipairs之类的函数将忽略此类条目,因为条目(关联)与值nil不被视为“表的一部分”。

序列

(如果表还不是很棘手)

在这个答案中,我谈论的是表一般,即对它们的键没有任何假设。在 Lua 中,具有特定键集的表可以称为序列,您可以使用 table.remove 从此类表中删除整数键。但是,首先,这个函数对于非序列(即一般的表)实际上是未定义的,其次,没有理由假设它不仅仅是一个 util,即可以使用原始操作在 Lua 中直接实现的东西。

哪些表是序列或不是序列是另一个棘手的话题,我不会在这里详细介绍。

参考参考文献

(确实不是我编的)

以上所有内容均基于官方语言参考手册。有趣的部分主要是章节 2.1 – 值和类型...

表可以是异构的;也就是说,它们可以包含所有类型的值(nil 除外)。任何值为 nil 的键都不被视为表的一部分。相反,任何不属于表的键都具有关联值 nil。

这部分的措辞并不完美。首先,我发现“表可以是异构的”这句话令人困惑。这是该术语在参考文献中的唯一使用,并且“可以”部分使得“异构”是否是表的可能属性,或者表是否变得不明显就是这样定义的。第二句话使第一个解释更加合理,因为如果“任何值为 nil 的键不被视为表的一部分”,那么就意味着“值为 nil 的键”并不矛盾。此外,rawset 函数的规范,它(间接)为 6.1 – 基本功能章节说...

将 table[index] 的实际值设置为 value,而不调用任何元方法。 table 必须是一个表,索引任何不同于 nil 和 NaN 的值,并赋值任何 Lua 值。

由于 nil 值在这里没有特殊情况,这意味着您可以 t[k] 设置为 <代码>零。理解这一点的唯一方法是接受从现在开始,该键将是“值为 nil 的键”,因此“不会被视为表的一部分”(pairs 将忽略它等),并且由于“任何不属于表的键都具有关联值 nil”,t[k] 将计算为 nil

整个参考文献也没有提到从任何其他地方的表中“删除”键或条目。

关于表的另一种视角

(如果您讨厌无穷大)

虽然我个人认为参考文献中的视角很优雅,但我也明白它与其他流行模型不同的事实可能会使其更难以推理。

我相信以下观点实际上等同于前一种观点。

您可以认为...

  • {} 返回一个表。
  • 如果 t 包含k,且 t[k] 计算结果为 v code>nil 否则
  • 设置 t[k] = v 插入一个新条目(k, v) 如果表不包含键 k,则更新该条目;如果 t 已包含键 k,则更新此类条目>,最后,作为特殊情况,如果v删除k的条目>nil
  • 表的内容(即被认为是“表的一部分”)是表中所有条目的集合。

在此模型中,表不能“包含“nil 值。

这不是语言参考定义事物的方式,但据我所知,这种模型显然是等效的。

不要谈论实现细节

(除非您确定这就是您的意思)

表的所谓“哈希映射部分”(它补充了表的所谓“数组部分” )是实现细节,除非我们讨论性能或特定未定义或实现定义的行为的解释,否则谈论它们在我看来在最好的情况下会令人困惑,在最坏的情况下是完全错误的。

例如,在这样构造的表中... t = {}, t[1] = 10, t[2] = 20 >, t[3] = 30,数组部分(可能!)为 [10, 20, 30] 并设置 t[2] = nil 将从“数组部分”“删除”条目 (2, 20),也可能调整其大小或移动 3 -> 。 30 到 hashmap 部分。我不太确定。我这么说只是为了证明讨论实现细节不是我们在这里想做的。

TLDR

(because you're only damn trying to remove a thing from a map, how hard can that be)

Setting a key to nil (e.g. t[k] = nil) is not only accepted and standard, but it's the only way of removing the entry from the table's "content" in general. And that makes sense. Also, array portion and hashmap portion are implementation details and shouldn't have ever be mentioned in this Q/A.

Understanding Lua's tables

(and why you can't remove from an infinite)

Lua tables don't literally have concept of "removing an entry from a table" and it hardly has a concept of "inserting an entry to a table". This is different from many other data structures from different programming languages.

In Lua, tables are modelling a perfect associative structure of infinite size.

Tables in Lua are inherently mutable and there's only one fundamental way to construct a new table: using the {} expression. Constructing a table with initial content (e.g. t = {10, 20, ["foo"] = 123, 30} or anything alike) is actually a syntactic sugar equivalent to first constructing a new table (e.g. t = {}} and then setting the "initial" entries one by one (e.g. t[1] = 10, t[2] = 20, t["foo"] = 123, t[3] = 30) . The details of how the de-sugaring works doesn't help with understanding the discussed matter, so I will be avoiding the table construction sugar in this answer.

In Lua, a freshly-constructed table initially associates all possible values with nil. That means that for a table t = {}, t[2] will evaluate to nil, t[100] will evaluate to nil, t["foo"] will evaluate to nil, t[{}] will evaluate to nil, etc.

After construction, you can mutate the table by setting a value at some key. Then that key will be now associated with that value. For example, after setting t["foo"] = "bar", the key "foo" will now be associated with the value "bar". In consequence, t["foo"] will now evaluate to "bar".

Setting nil at some key will associate that key to nil. For example, after setting t["foo"] = nil, "foo" will (again) be associated with nil. In consequence, t["foo"] will (again) evaluate to nil.

While any key can be associated to nil (and initially all possible keys are), such entries (key/value pairs) are not considered a part of the table (i.e. aren't considered part of the table content).

Functions pairs and ipairs (and multiple others) operate on table's content, i.e. the of associations in which the value isn't nil. The number of such associations is always finite.

Having everything said above in mind, associating a key with nil will probably do everything you could expect when saying "removing an entry from a table", because t[k] will evaluate to nil (like it did after constructing the table) and functions like pairs and ipairs will ignore such entries, as entries (associations) with value nil aren't considered "a part of the table".

Sequences

(if tables weren't already tricky)

In this answer, I'm talking about tables in general, i.e. without any assumption about their keys. In Lua, tables with a particular set of keys can be called a sequence, and you can use table.remove to remove an integer key from such table. But, first, this function is effectively undefined for non-sequences (i.e. tables in general) and, second, there's no reason to assume that it's more than a util, i.e. something that could be directly implemented in Lua using primitive operations.

Which tables are or aren't a sequence is another hairy topic and I won't get into details here.

Referencing the reference

(I really didn't make up all that)

Everything said above is based on the official language reference manual. The interesting parts are mostly chapter 2.1 – Values and Types...

Tables can be heterogeneous; that is, they can contain values of all types (except nil). Any key with value nil is not considered part of the table. Conversely, any key that is not part of a table has an associated value nil.

This part is not worded perfectly. First, I find the phrase "tables can be heterogeneous" confusing. It's the only use of this term in the reference and the "can be" part makes it non-obvious whether "being heterogeneous" is a possible property of a table, or whether it tables are defined that way. The second sentence make the first explanation more reasonable, because if "any key with value nil is not considered part of the table", then it means that "a key with value nil" is not a contradiction. Also, the specification of the rawset function, which (indirectly) gives semantics to the t[k] = v syntax, in the 6.1 – Basic Functions chapter says...

Sets the real value of table[index] to value, without invoking any metamethod. table must be a table, index any value different from nil and NaN, and value any Lua value.

As nil values are not special-cased here, that means that you can set t[k] to nil. The only way to understand that is to accept that from now on, that key will be "a key with value nil", and in consequence "will not be considered part of the table" (pairs will ignore it, etc.), and as "any key that is not part of a table has an associated value nil", t[k] will evaluate to nil.

The whole reference also doesn't mention "removing" a key or an entry from tables in any other place.

Another perspective on tables

(if you hate infinities)

While I personally find the perspective from the reference elegant, I also understand that the fact that it's different from other popular models might make it more difficult to reason about.

I believe that the following perspective is effectively equivalent to the previous one.

You can think that...

  • {} returns an empty table.
  • t[k] evaluates to v if t contains key k, and nil otherwise
  • Setting t[k] = v inserts a new entry (k, v) to the table if it doesn't contain key k, updates such entry if t already contains key k, and finally, as a special case, removes the entry for the key k if v is nil
  • The content of the table (i.e. what's considered "a part of the table") is the set of all entries from the table

In this model, tables aren't capable of "containing" nil values.

This is not how the language reference defines things, but to the best of my understanding, such model is observably equivalent.

Don't talk implementation details

(unless you're sure that that's what you mean)

The so-called "hashmap portion" of the table (which supplements the so-called "array portion" of the table) are implementation details and talking about them, unless we discuss performance or the explanation of specific undefined or implementation-defined behaviors, is in my opinion confusing in the best case and plain wrong in the worst.

For example, in a table constructed like this... t = {}, t[1] = 10, t[2] = 20, t[3] = 30, the array portion will (probably!) be [10, 20, 30] and setting t[2] = nil will "remove" the entry (2, 20) "from the array part", possibly also resizing it or moving 3 -> 30 to the hashmap part. I'm not really sure. I'm just saying this to prove that discussing implementation details is not what we want to do here.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文