数组 Table Array
table 是 Lua 中唯一的数据结构,其他语言所提供的数据结构,如:arrays、records、
lists、 queues、 sets 等,Lua 都是通过 table 来实现
在 lua 中通过整数下标访问 table 中元素,即是数组。并且数组大小不固定,可动态
增长。
数组是有序的对象的装置,它可以是包含含有多个行和列的行或多维阵列的集合的单
个二维数组。
一维数组
一维数组可以用一个简单的表结构来表示,可以初始化,使用一个简单的 for 循环读取。
如下例子所示。
-- 定义一维数组
a = {1, 2, 3, 4, 5}
-- 读取数组元素
for i = 1, #a do
print(a[i])
end
二维数组
二维数组可以用一个包含多个表的表结构来表示,可以初始化,使用两个 for 循环读取。
-- 定义二维数组
b = {
{1, 2, 3},
{4, 5, 6},
{7, 8, 9}
}
-- 读取二维数组元素
for i = 1, #b do
for j = 1, #b[i] do
print(b[i][j])
end
end
for i, v in ipairs(b) do
for j, w in ipairs(v) do
print(w)
end
end
table->array 库
# 运算符
运算符用于获取数组的长度。
a = {1, 2, 3, 4, 5}
print(#a) -- 5
拼接数组
table.concat 函数用于拼接数组。
table.concat(table, sep, start, end)
table: 要被拼接的数组或表。
sep (可选): 一个字符串,用于指定连接各个元素之间的分隔符。默认值是一个空字符串,即不使用任何分隔符。
start (可选): 指定开始拼接的索引,默认为 1。
end (可选): 指定结束拼接的索引,默认为表的最后一个元素。
特点
高效性: table.concat 在拼接大量元素时通常比使用简单的字符串拼接方式更高效。
支持范围拼接: 你可以选择拼接表中的部分元素,这在某些情况下非常有用。
灵活性: 可以通过选择不同的分隔符,灵活控制拼接后的字符串格式。
注意事项
table.concat 只能用于一维数组,不能直接用于包含嵌套表的多维数组。如果需要处理多维数组,你需要手动遍历每个表,然后使用 table.concat。
如果所拼接的表是空的,table.concat 的返回值将是一个空字符串。
local fruits = {"apple", "banana", "cherry"}
local result = table.concat(fruits)
print(result) -- 输出: applebananacherry
local fruits = {"apple", "banana", "cherry"}
local result = table.concat(fruits, ", ")
print(result) -- 输出: apple, banana, cherry
local numbers = {1, 2, 3, 4, 5}
local result = table.concat(numbers, "-", 2, 4)
print(result) -- 输出: 2-3-4
table.sort排序数组
table.sort 是 Lua 中用于对表(数组)进行排序的函数。它的基本作用是将一个一维数组中的元素按指定的顺序进行排序。以下是对 table.sort 的详细介绍。
table.sort(table, comp)
table: 需要排序的数组(表)。
comp (可选): 一个函数,用于自定义排序的规则。如果没有提供该函数,默认为升序排序。
默认排序
如果不提供比较函数,table.sort会按照元素的自然顺序进行排。
对于数字,默认是升序排序;对于字符串则是按照字母表的顺序排序。
local numbers = {5, 2, 8, 1, 4}
table.sort(numbers)
for _, v in ipairs(numbers) do
print(v) -- 输出: 1, 2, 4, 5, 8
end
自定义排序
你可以提供一个自定义的比较函数来控制排序的行为。
比较函数接收两个参数,应该返回 true 或 false,以便确定它们的顺序。
local names = {"Alice", "Bob", "Charlie"}
-- 自定义一个比较函数,使其按字符串长度排序
table.sort(names, function(a, b)
return #a < #b
end)
for _, v in ipairs(names) do
print(v) -- 输出: Bob, Alice, Charlie
end
只有一维数组(表)能使用 table.sort。
table.sort 是原地排序,这意味着它会直接改变传入的表,而不是返回一个新的排序表。
table.insert 插入元素
table.insert(table, [position,] value)
table: 要插入元素的目标数组或表。
position (可选): 插入元素的位置索引。如果指定,新的元素会插入到该位置,后面的元素会依次向后移动。如果不指定,默认会将元素追加到表的末尾。
value: 要插入的值或元素。
将元素插入到表的末尾
local fruits = {"apple", "banana"}
table.insert(fruits, "cherry") -- 在表的末尾插入元素
for _, v in ipairs(fruits) do
print(v) -- 输出: apple, banana, cherry
end
将元素插入到指定位置
local fruits = {"apple", "banana"}
table.insert(fruits, 2, "cherry") -- 在索引2的位置插入元素
for _, v in ipairs(fruits) do
print(v) -- 输出: apple, cherry, banana
end
插入多个元素(实现方式)
虽然 table.insert 只能一次插入一个元素,但可以通过循环来插入多个元素
local fruits = {"apple", "banana"}
local moreFruits = {"cherry", "date", "fig"}
for _, fruit in ipairs(moreFruits) do
table.insert(fruits, fruit) -- 将每个新元素插入到表的末尾
end
for _, v in ipairs(fruits) do
print(v) -- 输出: apple, banana, cherry, date, fig
end
table.insert 是原地操作,它直接改变传入的表,而不是返回一个新的表。
如果插入的索引超出表的当前长度,Lua 会自动在表的末尾插入这个元素。
如果插入的位置是负数,Lua 会将这个位置视为从表尾开始计算的索引。
打包 table.pack
table.pack 是 Lua 中用于将多个参数打包成一个表(table)元素的函数。这个函数在需要将多个值放在一个表中时非常有用,尤其是在处理可变数量的参数时。
table.pack(...)
...: 表示可变参数,允许传入任意数量的参数。
主要特性
打包参数: table.pack 可以接收一个或多个参数,并将其打包到一个表中。
包含元素数量: 生成的表会有一个 n 字段,表示实际元素的数量。这在进行遍历和索引时特别有用。
local packed = table.pack(1, 2, 3, "apple", "banana")
for i = 1, packed.n do
print(packed[i]) -- 输出: 1, 2, 3, apple, banana
end
table.pack 将多个参数打包成一个表 packed,并通过 packed.n 获取元素数量。
local packed = table.pack()
print(packed.n) -- 输出: 0
当没有传入任何参数时,table.pack 会返回一个空表,并且 n 的值为 0。
local packed = table.pack(1, nil, 3)
for i = 1, packed.n do
print(packed[i]) -- 输出: 1, nil, 3
end
table.pack 可以打包 nil 值,但仍然会将 n 设置为实际参数的数量,包括 nil。
使用场景
用户自定义函数的参数收集: 可用于函数接收不定数量的参数,并将它们打包成表。
数据传输: 在某些情况下,将多个值打包成表以便传递和处理会更便捷。
注意事项
使用 table.pack 时,如果需要访问返回表的元素,应该通过 packed.n 来获取元素数量,并在遍历时使用有效的索引。
table.pack 返回的表是一个普通表,可以像其他表一样使用。
解包 table.unpack
table.unpack 是 Lua 中用于将表(table)中的元素解包(提取)为多个参数的函数。这个函数非常有用,在需要将表中的值作为多个独立参数传递给函数时,特别方便。
table.unpack(table, [start], [end])
table: 要解包的表。
start (可选): 开始解包的索引,默认为 1。
end (可选): 结束解包的索引,默认为表的长度。
主要特性
提取表的元素: 将指定范围内的元素解包为独立的参数。
灵活的索引范围: 允许指定解包的起始和结束索引,以控制提取的元素范围。
local fruits = {"apple", "banana", "cherry"}
local a, b, c = table.unpack(fruits)
print(a) -- 输出: apple
print(b) -- 输出: banana
print(c) -- 输出: cherry
table.unpack 将 fruits 表中的元素解包为独立的变量 a、b 和 c。
local numbers = {10, 20, 30, 40, 50}
local first, second = table.unpack(numbers, 1, 2)
print(first) -- 输出: 10
print(second) -- 输出: 20
table.unpack 只解包 numbers 表中的前两个元素。
local empty = {}
local a, b, c = table.unpack(empty)
print(a) -- 输出: nil
print(b) -- 输出: nil
print(c) -- 输出: nil
当解包空表时,所有的变量都会被赋值为 nil。
使用场景
动态参数传递: 在函数调用时,可以使用 table.unpack 将表中的内容作为独立参数传入。
简化代码: 当需要从表中获取多个值时,使用 table.unpack 可以使代码更加简洁和易读。
注意事项
table.unpack 函数的参数要求是表。如果传入一个非表的值,会导致错误。
如果解包的范围超出表的长度,Lua 会自动将超出部分视为 nil。
删除 table.remove
table.remove 是 Lua 中用于从表(数组)中删除元素的函数。
这个函数非常实用,尤其是在需要动态地移除表中的某个元素时。
table.remove(table, [position])
table: 需要删除元素的目标数组(表)。
position (可选): 要删除的元素的索引。如果未指定,默认删除表中的最后一个元素。
local fruits = {"apple", "banana", "cherry"}
local removedFruit = table.remove(fruits)
print(removedFruit) -- 输出: cherry
for _, v in ipairs(fruits) do
print(v) -- 输出: apple, banana
end
table.remove 删除了 fruits 表中的最后一个元素,并返回了被删除的值。
local fruits = {"apple", "banana", "cherry"}
local removedFruit = table.remove(fruits, 2) -- 删除索引为 2 的元素
print(removedFruit) -- 输出: banana
for _, v in ipairs(fruits) do
print(v) -- 输出: apple, cherry
end
table.remove 删除了 fruits 表中索引为 2 的元素 "banana"。
local numbers = {1, 2, 3, 4, 5}
table.remove(numbers) -- 删除最后一个元素 5
for _, v in ipairs(numbers) do
print(v) -- 输出: 1, 2, 3, 4
end
table.remove 删除表中的最后一个元素
table.remove 是原地操作,它直接改变传入的表,而不是返回一个新的表。
删除元素后,表中的后续元素会自动向前移动,以填补删除的空位,这会影响元素的索引。
如果指定的索引大于表的长度,table.remove 不会执行任何操作,并且返回 nil。
拷贝 table.move
table.move 是 Lua 中用于移动数组元素的函数。
这个函数用于将一个表(数组)中的一段元素复制到另一个位置,可以用于数组元素的重排、复制或移动,非常方便。
table.move(source, start, end, dest, [metatable])
source: 源表(源数组),即要移动元素的表。
start: 源表中要移动开始的索引位置(包括该位置)。
end: 源表中要移动结束的索引位置(包括该位置)。
dest: 目标表中插入元素的起始位置。
metatable (可选): 如果为真,目标表会保持源表的元表不变。
主要特性
table.move 可以用来移动源表中的一段元素,写入到目标表的指定位置。
该函数可以同时支持正向和反向的移动。
可以有效处理重叠的区域或不重叠的区域。
local fruits = {"apple", "banana", "cherry", "date", "fig"}
table.move(fruits, 2, 4, 1) -- 将索引 2 到 4 的元素移动到索引 1 位置
for _, v in ipairs(fruits) do
print(v) -- 输出: banana, cherry, date, date, fig
end
banana、cherry 和 date 被移动到表的前面,原来的元素被覆盖。
local numbers = {1, 2, 3, 4, 5}
table.move(numbers, 1, 3, 2) -- 将索引 1 到 3 的元素移动到索引 2 位置
for _, v in ipairs(numbers) do
print(v) -- 输出: 1, 1, 2, 3, 5
end
1、2、3 被移动到 2 的位置,且原有位置的元素将随着移动进行覆盖。
local letters = {"a", "b", "c", "d", "e"}
table.move(letters, 2, 4, 1) -- 将 `b`、`c` 和 `d` 移动到 `1` 位置
for _, v in ipairs(letters) do
print(v) -- 输出: b, c, d, d, e
end
b、c 和 d 被移动到表的开头,原有的开头元素被覆盖。
长度#
t = {11,22,33,44,55,66}
print(t[#t]) -- 输出最后一个元素 66
t[#t] = nil -- 移除最后一个元素
t[#t +1 ] = 999 -- 把 999 添加到序列最后
print(t[#t]) -- 999
#失效
print(#{1, 2, nil, 3}) -- 4
print(#{1, 2, nil, 3, nil}) --2
# ipairs 失效
数组中的 nil 影响求长度,长度不定的数组,无法通过下标对其遍历,迭代函数 ipairs
遍历则会中止。
array = {1,2,3,4,5,6,7,8,9,10}
print("len =",#array)
for k,v in ipairs(array) do
print(k,v)
end
print("====================")
array2 = {1,2,3,4,nil,6,7,8,9,10}
print("len =",#array2)
for k,v in ipairs(array2) do
print(k,v)
end
print("--------------------")
for i=1,#array2 do
print(i,array2[i])
end
len = 10
1 1
2 2
3 3
4 4
5 5
6 6
7 7
8 8
9 9
10 10
====================
len = 10
1 1
2 2
3 3
4 4
--------------------
1 1
2 2
3 3
4 4
5 nil
6 6
7 7
8 8
9 9
10 10
pairs有效
array2 = {11,22,33,44,nil,66,77,88,99,100,nil}
for k,v in pairs(array2) do
print(k,v) --pairs 打印的时候,nil 是不输出的。
end
1 11
2 22
3 33
4 44
6 66
7 77
8 88
9 99
10 100
在 Lua 中,pairs 和 ipairs 都是用于遍历表(数组和字典)的函数,但它们有一些重要的区别。以下是两者的主要区别:
- 遍历方式
ipairs:
仅用于遍历一维数组(即表中的整数索引元素)。
按照索引从 1 开始,连续遍历,每次迭代返回下一个索引和对应的值。
遇到第一个 nil 值时停止迭代。
local fruits = {"apple", "banana", "cherry", nil, "date"}
for index, value in ipairs(fruits) do
print(index, value)
end
-- 输出:
-- 1 apple
-- 2 banana
-- 3 cherry
pairs:
用于遍历表中的所有键值对。
可用于所有类型的表,无论是数值索引还是字符串索引。
不保证返回元素的顺序。
local fruits = {["a"] = "apple", ["b"] = "banana", ["c"] = "cherry"}
for key, value in pairs(fruits) do
print(key, value)
end
-- 输出(顺序可能不固定):
-- a apple
-- b banana
-- c cherry
- 应用场景
ipairs:
更适合用于遍历数组,特别是没有 nil 值的连续索引表。
常用于处理有序数据。
pairs:
更适合用于遍历包含混合类型键(如数字和字符串)和不连续键的表(即散列表)。
通常用于字典结构或以键值对形式的数据。
- 停止条件
ipairs:
一旦遇到第一个 nil 值,它将停止迭代。因此,如果数组中存在 nil,后续元素将不会被遍历。
pairs:
会遍历表中的所有元素,无论元素是否为 nil。它返回的是整个表的所有键值对,包含任何形式的 nil 值。