Pairs and IPairs on Table#

pairs 和 ipairs 功能初探#

pairs 和 ipairs 是两个标准库中的函数, 用于从 Table 数据结构中遍历元素. 简单说来, pairs 是用于遍历 Hash Table (类似于 Python dict) 中的 key, value pair 的, 类似于 Python 中的 dict.items() 方法. 而 ipairs 是用于遍历 Array Table (类似于 Python list) 中的 index 和 item 的, 类似于 Python 中的 enumerate(list) 方法.

下面是从 官方文档 中摘抄的定义.

pairs (t)

如果 t 有元方法 __pairs, 以 t 为参数调用它, 并返回其返回的前三个值.

否则, 返回三个值: next 函数, 表 t, 以及 nil. 因此以下代码:

for k, v in pairs(t) do body end

能迭代表 t 中的所有键值对.

参见函数 next 中关于迭代过程中修改表的风险.

ipairs (t)

返回三个值 (迭代函数, 表 t 以及 0 ), 如此, 以下代码:

for i,v in ipairs(t) do body end

将迭代键值对(1, t[1]), (2, t[2]), … , 直到第一个空值.

下面是一个大多数人使用这两个函数的例子

test0.lua
 1#!/usr/bin/env lua
 2
 3--[[
 4pairs 和 ipairs 的常见用法.
 5--]]
 6
 7
 8--[[
 9可能的输出 (顺序可能不同):
10
11key = a, value = 100, arg3 = nil
12key = c, value = 300, arg3 = nil
13key = b, value = 200, arg3 = nil
14--]]
15print("===== pairs =====")
16local pythonDict = {a = 100, b = 200, c = 300}
17for key, value in pairs(pythonDict) do
18    print(string.format("key = %s, value = %s", key, value))
19end
20
21--[[
22输出 (Lua 中 index 是从 1 开始的):
23
24index = 1, value = a
25index = 2, value = b
26index = 3, value = c
27--]]
28print("===== ipairs =====")
29local pythonList = {"a", "b", "c"}
30for index, value in ipairs(pythonList) do
31    print(string.format("index = %s, value = %s", index, value))
32end
[1]:
import subprocess

subprocess.run(["lua", "test0.lua"]);
===== pairs =====
key = b, value = 200
key = c, value = 300
key = a, value = 100
===== ipairs =====
index = 1, value = a
index = 2, value = b
index = 3, value = c

Example 1#

从这个例子可以看出, 对于 key 不是从 1 开始的整数的 Hash Table, ipairs 没有效果.

test1.lua
 1#!/usr/bin/env lua
 2
 3--[[
 4pairs:
 5
 6- 用于遍历表中的所有键值对
 7- 遍历顺序不确定
 8- 可以处理任何类型的键(包括字符串、数字等)
 9
10ipairs:
11
12- 用于遍历数组部分(即使用连续整数索引的部分)
13- 按照索引的数字顺序遍历
14- 遇到 nil 值或非整数键时停止
15--]]
16
17local pythonDict = {
18    a = 100,
19    b = 200,
20    c = 300,
21}
22
23--[[
24可能的输出 (顺序可能不同):
25
26key = a, value = 100, arg3 = nil
27key = c, value = 300, arg3 = nil
28key = b, value = 200, arg3 = nil
29--]]
30
31print("===== pairs =====")
32for arg1, arg2, arg3 in pairs(pythonDict) do
33    print(string.format("key = %s, value = %s, arg3 = %s", arg1, arg2, arg3))
34end
35
36--[[
37输出: (无输出)
38解释: 由于这个表没有使用整数索引, ipairs 不会遍历任何元素.
39--]]
40print("===== ipairs =====")
41for arg1, arg2, arg3 in ipairs(pythonDict) do
42    print(string.format("key = %s, value = %s, arg3 = %s", arg1, arg2, arg3))
43end
[2]:
subprocess.run(["lua", "test1.lua"]);
===== pairs =====
key = a, value = 100, arg3 = nil
key = b, value = 200, arg3 = nil
key = c, value = 300, arg3 = nil
===== ipairs =====

Example 2#

从这个例子可以看出, 对于 key 不是从 1 开始的整数的 Hash Table, ipairs 没有效果. 只要数字不是 1, 2, 3, …, 就不可以. 因为它本质上是返回 (1, table[1]), (2, table[2]), … 直到碰到第一个 nil 为止. 在这种情况下第一个就是 nil, 所以什么也没有返回.

test2.lua
 1#!/usr/bin/env lua
 2
 3local pythonDict = {
 4    [100] = "a",
 5    [200] = "b",
 6    [300] = "3",
 7}
 8
 9--[[
10输出:
11
12key = 300, value = 3, arg3 = nil
13key = 100, value = a, arg3 = nil
14key = 200, value = b, arg3 = nil
15--]]
16print("===== pairs =====")
17for arg1, arg2, arg3 in pairs(pythonDict) do
18    print(string.format("key = %s, value = %s, arg3 = %s", arg1, arg2, arg3))
19end
20
21--[[
22输出: (无输出)
23解释: 由于这个表没有使用整数索引, ipairs 不会遍历任何元素.
24--]]
25print("===== ipairs =====")
26for arg1, arg2, arg3 in ipairs(pythonDict) do
27    print(string.format("key = %s, value = %s, arg3 = %s", arg1, arg2, arg3))
28end
[3]:
subprocess.run(["lua", "test2.lua"]);
===== pairs =====
key = 300, value = 3, arg3 = nil
key = 100, value = a, arg3 = nil
key = 200, value = b, arg3 = nil
===== ipairs =====

Example 3#

对于 key 是从整数开始的 Hash Table, ipairs 是有效果的.

test3.lua
 1#!/usr/bin/env lua
 2
 3local pythonDict = {
 4    [1] = "a",
 5    [2] = "b",
 6    [3] = "c",
 7}
 8
 9print("===== pairs =====")
10for arg1, arg2, arg3 in pairs(pythonDict) do
11    print(string.format("key = %s, value = %s, arg3 = %s", arg1, arg2, arg3))
12end
13
14--[[
15由于该表采用了整数索引, 所以可以用 ipairs. 输出:
16
17key = 1, value = a, arg3 = nil
18key = 2, value = b, arg3 = nil
19key = 3, value = c, arg3 = nil
20--]]
21print("===== ipairs =====")
22for arg1, arg2, arg3 in ipairs(pythonDict) do
23    print(string.format("key = %s, value = %s, arg3 = %s", arg1, arg2, arg3))
24end
[4]:
subprocess.run(["lua", "test3.lua"]);
===== pairs =====
key = 3, value = c, arg3 = nil
key = 1, value = a, arg3 = nil
key = 2, value = b, arg3 = nil
===== ipairs =====
key = 1, value = a, arg3 = nil
key = 2, value = b, arg3 = nil
key = 3, value = c, arg3 = nil

Example 4#

从这个例子可以看出, 对于 Array Table, pairs 返回的 key 会是 1, 2, 3, …

test4.lua
 1#!/usr/bin/env lua
 2
 3local pythonList = {
 4    "a",
 5    "b",
 6    "c"
 7}
 8
 9--[[
10输出:
11
12key = 1, value = a, arg3 = nil
13key = 2, value = b, arg3 = nil
14key = 3, value = c, arg3 = nil
15--]]
16print("===== pairs =====")
17for arg1, arg2, arg3 in pairs(pythonList) do
18    print(string.format("key = %s, value = %s, arg3 = %s", arg1, arg2, arg3))
19end
20
21--[[
22输出:
23
24key = 1, value = a, arg3 = nil
25key = 2, value = b, arg3 = nil
26key = 3, value = c, arg3 = nil
27--]]
28print("===== ipairs =====")
29for arg1, arg2, arg3 in ipairs(pythonList) do
30    print(string.format("key = %s, value = %s, arg3 = %s", arg1, arg2, arg3))
31end
32
33--[[
34对于列表, 输出就是 index 和 value, 跟 python 中的 enumerate 函数类似. 输出:
35
36key = 1, value = a
37key = 2, value = b
38key = 3, value = c
39--]]
40print("===== ipairs =====")
41for arg1, arg2 in ipairs(pythonList) do
42    print(string.format("key = %s, value = %s", arg1, arg2))
43end
[5]:
subprocess.run(["lua", "test4.lua"]);
===== pairs =====
key = 1, value = a, arg3 = nil
key = 2, value = b, arg3 = nil
key = 3, value = c, arg3 = nil
===== ipairs =====
key = 1, value = a, arg3 = nil
key = 2, value = b, arg3 = nil
key = 3, value = c, arg3 = nil
===== ipairs =====
key = 1, value = a
key = 2, value = b
key = 3, value = c

Example 5#

从这个例子可以看出, 对于 Array Table, pairs 返回的 key 会是 1, 2, 3, …

test5.lua
 1#!/usr/bin/env lua
 2
 3local pythonList = {
 4    100,
 5    200,
 6    300
 7}
 8
 9--[[
10输出:
11
12key = 1, value = 100, arg3 = nil
13key = 2, value = 200, arg3 = nil
14key = 3, value = 300, arg3 = nil
15--]]
16print("===== pairs =====")
17for arg1, arg2, arg3 in pairs(pythonList) do
18    print(string.format("key = %s, value = %s, arg3 = %s", arg1, arg2, arg3))
19end
20
21--[[
22输出:
23
24key = 1, value = 100, arg3 = nil
25key = 2, value = 200, arg3 = nil
26key = 3, value = 300, arg3 = nil
27--]]
28print("===== ipairs =====")
29for arg1, arg2, arg3 in ipairs(pythonList) do
30    print(string.format("key = %s, value = %s, arg3 = %s", arg1, arg2, arg3))
31end
[6]:
subprocess.run(["lua", "test5.lua"]);
===== pairs =====
key = 1, value = 100, arg3 = nil
key = 2, value = 200, arg3 = nil
key = 3, value = 300, arg3 = nil
===== ipairs =====
key = 1, value = 100, arg3 = nil
key = 2, value = 200, arg3 = nil
key = 3, value = 300, arg3 = nil

Example 6#

test6.lua
 1#!/usr/bin/env lua
 2
 3local pythonList = {
 4    1,
 5    2,
 6    3
 7}
 8
 9--[[
10输出:
11
12key = 1, value = 1, arg3 = nil
13key = 2, value = 2, arg3 = nil
14key = 3, value = 3, arg3 = nil
15--]]
16print("===== pairs =====")
17for arg1, arg2, arg3 in pairs(pythonList) do
18    print(string.format("key = %s, value = %s, arg3 = %s", arg1, arg2, arg3))
19end
20
21--[[
22输出:
23
24key = 1, value = 1, arg3 = nil
25key = 2, value = 2, arg3 = nil
26key = 3, value = 3, arg3 = nil
27--]]
28print("===== ipairs =====")
29for arg1, arg2, arg3 in ipairs(pythonList) do
30    print(string.format("key = %s, value = %s, arg3 = %s", arg1, arg2, arg3))
31end
[7]:
subprocess.run(["lua", "test6.lua"]);
===== pairs =====
key = 1, value = 1, arg3 = nil
key = 2, value = 2, arg3 = nil
key = 3, value = 3, arg3 = nil
===== ipairs =====
key = 1, value = 1, arg3 = nil
key = 2, value = 2, arg3 = nil
key = 3, value = 3, arg3 = nil
[ ]: