Chapter 20_1 table库
table库是由一些辅助函数构成,把table作为数组来操作,所有的函数都忽略传入参数的那张表中的非数字键。
无论如何,若一个操作需要取表的长度,这个表必须是一个真序列,或是拥有__len元方法。
提供了这样一些功能:从列表中插入和删除元素、对元素排序、连接一个数组中所有字符串。
- 插入和删除
函数table.insert用于将一个元素插入到一个数组指定位置,然后移动后续元素。
例如数组t = {10,20,30},当调用table.insert(t,1,15)后,t = {15,10,20,30}
如果insert函数没有指定位置参数,则会自动添加到数组末尾。
下面示例逐行读取输入,并将所有的行保存在一个数组中:
t = {} for line in io.lines() do table.insert(t , line) end print(#t) -->读入的行数
在Lua5.0的老版本中,这样写很正常,但是在最新的版本中,作者建议这样写:
t[#t+1] = line --替换insert
函数table.remove会删除(并返回)数组指定位置上的元素,然后后面的元素前移。
当没有指定位置参数时,会删除最后一个元素。
通过这两个函数可以很方便地实现栈、队列、双向队列。可以用t = {}来初始化这种结构。
table.insert(t, x )等价于压入操作。
table.remove(t) 等价于弹出操作。
table.insert(t , 1 ,x )在结构的另一端插入一个新元素。
table.remove(t , 1 )会从这一端删除一个元素。
后两个操作不是很高效,因为必须移动元素。针对较小的数组可以这样使用。
- 排序
另一个有用的数组函数table.sort,之前在高阶函数中提到过。它可以对一个数组进行排序,可以指定一个可选的排序函数。
这个排序函数必须是一个可以接收两个列表内元素为参数的函数,如果希望第一个参数在排序结果中位于第二个参数值前,就应当返回true。
再次重现之前的例子:
network = { {name = "arauna", IP = "210.26.20.30"}, {name = "brraial", IP = "210.26.45.33"}, {name = "lua", IP = "210.45.34.56"}, {name = "derain", IP = "210.26.23.76"}, } table.sort( network, function (a,b) --这里的a,b参数分别是列表里的两个元素 return (a.name < b.name) -- "arauna" < "brraial" 为真,所以下面打印是按照name的升序打印 end ) for k,v in pairs(network) do print(k,v.name) end -->1 arauna -->2 brraial -->3 derain -->4 lua
一个常见的错误是试图对一个table的索引进行排序。在table中,索引是一个无序的集合。
如果对它进行排序,则必须将它们复制到一个数组中,然后再对它进行排序。
下面演示一个示例:假设要读取一个源文件,并构建一个table记录每个函数并定义它的行号,table如下 :
lines = { luaH_set = 10, luaH_get = 24, luaH_present = 48, }
现在要按照字母次序打印这些函数名。如果用pairs来遍历table,结果是无序的。由于这些名称是table的key,因此不能对她们进行直接排序。
应该先放在一个数组中排序:
a = {} for n in pairs(lines) do a[#a+1] = n end table.sort(a) --对数组排序,按照默认的小于操作,结果为假,所以打印的是升序排列 for i , n in ipairs(a) do print(n) end --> luaH_get --> luaH_present --> luaH_set
对于Lua来说,数组也是无序的,它们本质也是table。然而用户知道如何计算索引,因此在访问数组时,只要使用有序的索引,就可以顺序地访问数组。
这就是为什么必须要使用ipairs而不是pairs来遍历数组的原因。因为前者使用1、2、3....的顺序,后者采用table的原始顺序。
另一个更高级的方法,写一个迭代器,使它根据table key的次序来进行遍历。同时,还有一个可选的参数f,用于指定某种特殊次序:
function parisByKeys(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]] --返回原table中的key和value,即函数名和行号 end end
该函数先将key 排序到一个数组中,然后迭代这个数组,每步返回原table中的key和value。
通过这个函数就可以很容易地按照字母次序来打印那些函数名了:
for name , line in pairsByKeys(lines) do print(name,line) end
- 连接
之前也用到过table.connect,它接受一个字符串数组,并返回这些字符串连接后的结果。
它有一个可选参数,用于指定插到字符串之间的分隔符。
这个函数另外还接受两个可选参数,用于指定第一个和最后一个要连接的字符串索引。
下面这个函数是table.connect的一个扩展,它能处理嵌套的字符串数组:
function rconcat( t ) if type(t) ~= "table" then return r end local res = {} for i = 1 , #t do res[i] = rconcat(t[i]) --递归调用自己,以此来连接所有可能嵌套的字符串数组。 end return table.concat(res) end
最后调用concat来连接这些结果:
print(rconcat{{"a",{" nice"}} , " and",{{" long"}, {" list"}}}) --> a nice and long list
- 扩展两个有用的函数
table.pack(...)函数返回一个新表,以1、2、3...为key,参数为值的新表。并将“n”这个域设置为参数的总和。
这个新表不一定是一个序列。
table.unpack(list)函数返回列表中的元素,可以加两个参数i ,j 表示要返回的起始索引对应的值。
等价于:
return list[i],list[i+1]......,list[j]
所以,如果不设置i 和j ,就表示默认从1到#list
以上内容来自:《Lua程序设计第二版》和《Programming in Lua third edition 》 和 Lua参考手册