无法使用关联索引对表进行排序

发布于 2024-08-18 09:43:20 字数 41 浏览 8 评论 0原文

为什么我不能使用 table.sort 对具有关联索引的表进行排序?

Why I can't use table.sort to sort tables with associative indexes?

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

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

发布评论

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

评论(3

别想她 2024-08-25 09:43:20

一般来说,Lua 表是纯关联数组。除了作为 Lua 核心中使用的特定哈希表实现的副作用之外,不存在“自然”顺序。这是有道理的,因为任何 Lua 数据类型的值(nil 除外)都可以用作键和值;但只有字符串和数字具有任何类型的合理排序,并且仅在类似类型的值之间。

例如,这张表的排序顺序应该是:

unsortable = {
    answer=42,
    true="Beauty",
    [function() return 17 end] = function() return 42 end,
    [math.pi] = "pi",
    [ {} ] = {},
    12, 11, 10, 9, 8
}

它有 1 个字符串键、1 个布尔键、1 个功能键、1 个非整数键、1 个表键和 5 个整数键。该函数应该在字符串之前排序吗?如何将字符串与数字进行比较?表格应该在哪里排序?那么恰好没有出现在该表中的 userdatathread 值又如何呢?

按照惯例,由从 1 开始的连续整数索引的值通常用作列表。一些函数和常见的习惯用法都遵循这一约定,table.sort 就是一个例子。对列表进行操作的函数通常会忽略存储在不属于列表的键中的任何值。同样,table.sort 是一个示例:它仅对存储在列表中的键处的元素进行排序。

另一个例子是# 运算符。对于上表,#unsortable 为 5,因为 unsortable[5] ~= nilunsortable[6] == nil。请注意,即使 pi 介于 3 和 4 之间,存储在数字索引 math.pi 中的值也不会被计算在内,因为它不是整数。此外,其他非整数键也不会被计算在内。这意味着一个简单的 for 循环可以迭代整个列表:

for i in 1,#unsortable do
    print(i,unsortable[i])
end

尽管这通常被写为

for i,v in ipairs(unsortable) do
    print(i,v)
end

简而言之,Lua 表是无序的值集合,每个值都由一个键索引;但对于从 1 开始的连续整数键有一个特殊约定。

编辑:对于具有适当部分排序的非整数键的特殊情况,有一个涉及单独索引表的解决方法。由字符串值作为键的表的描述内容是此技巧的合适示例。

首先,以列表的形式收集新表中的键。也就是说,创建一个表,该表由从 1 开始的连续整数索引,并以键作为值,然后对其进行排序。然后,使用该索引以所需的顺序迭代原始表。

例如,这里是 foreachinorder(),它使用此技术迭代表的所有值,按照比较函数确定的顺序为每个键/值对调用一个函数。

function foreachinorder(t, f, cmp)
    -- first extract a list of the keys from t
    local keys = {}
    for k,_ in pairs(t) do
        keys[#keys+1] = k
    end
    -- sort the keys according to the function cmp. If cmp
    -- is omitted, table.sort() defaults to the < operator
    table.sort(keys,cmp)
    -- finally, loop over the keys in sorted order, and operate
    -- on elements of t
    for _,k in ipairs(keys) do
        f(k,t[k])
    end
end

它构建一个索引,使用 table.sort 对其进行排序(),然后循环遍历排序索引中的每个元素,并为每个元素调用函数 f。函数 f 传递键和值。排序顺序由传递给 table.sort 的可选比较函数确定。它通过两个要比较的元素(在本例中为表 t 的键)来调用,并且如果第一个元素小于第二个元素,则必须返回 true。如果省略,table.sort 使用内置的 < 运算符。

例如,给定下表:

t1 = {
    a = 1,
    b = 2,
    c = 3,
}

然后 foreachinorder(t1,print) 打印:

a    1
b    2
c    3

并且 foreachinorder(t1,print,function(a,b) return a>b end)印刷:

c    3
b    2
a    1

In general, Lua tables are pure associative arrays. There is no "natural" order other than the as a side effect of the particular hash table implementation used in the Lua core. This makes sense because values of any Lua data type (other than nil) can be used as both keys and values; but only strings and numbers have any kind of sensible ordering, and then only between values of like type.

For example, what should the sorted order of this table be:

unsortable = {
    answer=42,
    true="Beauty",
    [function() return 17 end] = function() return 42 end,
    [math.pi] = "pi",
    [ {} ] = {},
    12, 11, 10, 9, 8
}

It has one string key, one boolean key, one function key, one non-integral key, one table key, and five integer keys. Should the function sort ahead of the string? How do you compare the string to a number? Where should the table sort? And what about userdata and thread values which don't happen to appear in this table?

By convention, values indexed by sequential integers beginning with 1 are commonly used as lists. Several functions and common idioms follow this convention, and table.sort is one example. Functions that operate over lists usually ignore any values stored at keys that are not part of the list. Again, table.sort is an example: it sorts only those elements that are stored at keys that are part of the list.

Another example is the # operator. For the above table, #unsortable is 5 because unsortable[5] ~= nil and unsortable[6] == nil. Notice that the value stored at the numeric index math.pi is not counted even though pi is between 3 and 4 because it is not an integer. Furthermore, none of the other non-integer keys are counted either. This means that a simple for loop can iterate over the entire list:

for i in 1,#unsortable do
    print(i,unsortable[i])
end

Although that is often written as

for i,v in ipairs(unsortable) do
    print(i,v)
end

In short, Lua tables are unordered collections of values, each indexed by a key; but there is a special convention for sequential integer keys beginning at 1.

Edit: For the special case of non-integral keys with a suitable partial ordering, there is a work-around involving a separate index table. The described content of tables keyed by string values is a suitable example for this trick.

First, collect the keys in a new table, in the form of a list. That is, make a table indexed by consecutive integers beginning at 1 with keys as values and sort that. Then, use that index to iterate over the original table in the desired order.

For example, here is foreachinorder(), which uses this technique to iterate over all values of a table, calling a function for each key/value pair, in an order determined by a comparison function.

function foreachinorder(t, f, cmp)
    -- first extract a list of the keys from t
    local keys = {}
    for k,_ in pairs(t) do
        keys[#keys+1] = k
    end
    -- sort the keys according to the function cmp. If cmp
    -- is omitted, table.sort() defaults to the < operator
    table.sort(keys,cmp)
    -- finally, loop over the keys in sorted order, and operate
    -- on elements of t
    for _,k in ipairs(keys) do
        f(k,t[k])
    end
end

It constructs an index, sorts it with table.sort(), then loops over each element in the sorted index and calls the function f for each one. The function f is passed the key and value. The sort order is determined by an optional comparison function which is passed to table.sort. It is called with two elements to compare (the keys to the table t in this case) and must return true if the first is less than the second. If omitted, table.sort uses the built-in < operator.

For example, given the following table:

t1 = {
    a = 1,
    b = 2,
    c = 3,
}

then foreachinorder(t1,print) prints:

a    1
b    2
c    3

and foreachinorder(t1,print,function(a,b) return a>b end) prints:

c    3
b    2
a    1
红墙和绿瓦 2024-08-25 09:43:20

您只能对具有从 1 开始的连续整数键的表(即列表)进行排序。如果您有另一个键值对表,您可以创建一个键值对列表并对其进行排序:

function sortpairs(t, lt)
  local u = { }
  for k, v in pairs(t) do table.insert(u, { key = k, value = v }) end
  table.sort(u, lt)
  return u
end

当然,仅当您提供需要作为参数 key/ 的自定义排序 (lt) 时,这才有用值对。

有关 Lua 表排序的相关问题中更详细地讨论了这个问题< /a>.

You can only sort tables with consecutive integer keys starting at 1, i.e., lists. If you have another table of key-value pairs, you can make a list of pairs and sort that:

function sortpairs(t, lt)
  local u = { }
  for k, v in pairs(t) do table.insert(u, { key = k, value = v }) end
  table.sort(u, lt)
  return u
end

Of course this is useful only if you provide a custom ordering (lt) which expects as arguments key/value pairs.

This issue is discussed at greater length in a related question about sorting Lua tables.

婴鹅 2024-08-25 09:43:20

因为他们一开始就没有任何订单。这就像试图对装满香蕉的垃圾袋进行分类一样。

Because they don't have any order in the first place. It's like trying to sort a garbage bag full of bananas.

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