按顺序遍历表

简介: 按顺序遍历表

一个常见的困惑

开发人员想要对表中的元素进行排序时。由于一个表中的元素没有顺序,所以如果想对这些元素排序,就不得不先把键值拷贝到一个数组中,然后再对数组进行排序。


假如我们要读取一个源文件,然后构造一个表来保存每个函数的名称及其生命所在的行数,形式如下:

lines = {
  ["luaH_set"] = 10,
  ["luaH_get"] = 24,
  ["luaH_present"] = 48,
}


现在,我们想按照字母顺序输出这些函数名。如果使用 pairs 遍历表,那么函数名会随机出现。由于这些函数名是表的键,所以我们无法直接对其进行排序。不过,如果我们把他们放到数组中,那么就可以对他们进行排序了。


首先,我们必须创建一个包含函数名的数组,然后对其排序,再最终输出结果。

a = {}
for n in pairs(lines) do a[#a + 1] = n end
table.sort(a)
for _, n in ipairs(a) do print(n) end


有些人可能会困惑,毕竟,对于 Lua 语言来说,数组也没有顺序(毕竟他们是表)。但是我们知道如何数数!因此,当我们使用有序的索引访问数组时,就实现了有序。这正是应该总是使用 ipars 而不是 pairs 来遍历数组的原因。第一个函数通过有序的键 12 等来实现有序,然而后者使用的则是天然的随机顺序(虽然大多数情况下顺序随机也无碍,但有时可能并非我们想要的)。


现在,我们已经准备好写一个按照键的顺序来遍历表的迭代器了。

function pairsByKeys (t, f)
  local a = {}
  for n in pairs(t) do                  --> 创建一个包含所有键的表
    a[#a + 1] = n
  end
  table.sort(a, f)                      --> 对列表排序
  local i = 0
  return function ()                    --> 迭代函数
    i = i +1
    return a[i], t[a[i]]                --> 返回键和值
  end
end


工厂函数 pairsByKeys 首先把键放到一个数组中,然后对数组进行排序,最后返回迭代函数。在每一步中,迭代器都会按照数组a 中的顺序返回原始表中的一个键值对。可选参数f 允许指定一种其他的排序方式。


使用这个上述函数,可以很容易得解决开始时提出的按照顺序遍历表的问题:

for name, line in pairsByKeys(lines) do
  print(name,line)
end


像通常一样,所有的复杂性都被隐藏到了迭代器中。

目录
相关文章
顺序表应用6:有序顺序表查询
顺序表应用6:有序顺序表查询
|
Linux C++
合并k个已排序的链表
合并k个已排序的链表
35 0
|
7月前
|
存储 搜索推荐 算法
【数据结构】排序(插入、选择、交换、归并) -- 详解(上)
【数据结构】排序(插入、选择、交换、归并) -- 详解(上)
|
7月前
|
人工智能 搜索推荐 算法
【数据结构】排序(插入、选择、交换、归并) -- 详解(下)
【数据结构】排序(插入、选择、交换、归并) -- 详解(下)
|
C++
【C/C++练习】合并k个已排序的链表(一)
【C/C++练习】合并k个已排序的链表(一)
81 0
|
7月前
|
算法 测试技术 C#
【哈希映射】【 哈希集合】 381. O(1) 时间插入、删除和获取随机元素 - 允许重复
【哈希映射】【 哈希集合】 381. O(1) 时间插入、删除和获取随机元素 - 允许重复
|
7月前
顺序排号
顺序排号。
57 5
|
C++
【C/C++练习】合并k个已排序的链表(二)
【C/C++练习】合并k个已排序的链表(二)
87 0
【C/C++练习】合并k个已排序的链表(二)
|
JSON 数据格式 Python
一日一技:包含非hashable元素的列表如何去重并保持顺序?
一日一技:包含非hashable元素的列表如何去重并保持顺序?
114 0
|
存储 前端开发 程序员
合并两个排序的链表
合并两个排序的链表
合并两个排序的链表