1

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

4

3 回答 3

6

通常,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
}

它有一个字符串键、一个布尔键、一个功能键、一个非整数键、一个表键和五个整数键。函数是否应该在字符串之前排序?你如何将字符串与数字进行比较?表格应该在哪里排序?那些没有出现在这个表中的值呢userdatathread

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

另一个例子是#运营商。对于上表,#unsortable是 5,因为unsortable[5] ~= nilunsortable[6] == nilmath.pi请注意,即使 pi 介于 3 和 4 之间,存储在数字索引中的值也不会被计算在内,因为它不是整数。此外,也不计算其他非整数键。这意味着一个简单的 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)打印:

一个 1
b 2
3

foreachinorder(t1,print,function(a,b) return a>b end)打印:

3
b 2
一个 1
于 2010-01-19T23:14:35.147 回答
3

您只能对具有从 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

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

这个问题在有关排序 Lua 表的相关问题中有更详细的讨论。

于 2010-01-20T09:41:14.163 回答
2

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

于 2010-01-19T21:58:23.403 回答