L3-07. table类型

一. 基本知识

  1. table是Lua的一种数据结构用来帮助我们创建不同的数据类型,如:数组、字典等。

  2. Lua的table数据类型,可以用任意类型来作数组的索引,但这个值不能是 nil。

  3. Lua table 是不固定大小的,是一个动态表, 自动随心扩容

  4. Lua也是通过table来解决模块、包和对象的。 例如string.format表示使用"format"来索引table string。

二. table的构造

  1. table使用"{}"大括号进行创建表或初始化表

复制代码
--定义一个空表
local mytable = {}
-- 指定值
mytable[1]= "Lua"
-- 移除引用
mytable = nil
-- lua 垃圾回收会释放内存

--定义并初始化一个表, 这种写法可以避免添加值时, 进行重新哈希, 可以有效提高执行效率 local t2 = {"nil","nil","nil","nil"}
复制代码

  2. 避免重新哈希, 提高执行效率

复制代码
--Lua也会为哈希部分创建一个大小为4的数组。例如,执行下面的代码需要2.0秒:
for i = 1, 1000000 do
    local a = {}
    a[1] = 1; a[2] = 2; a[3] = 3
end

--如果在创建表时给定正确的大小,执行时间可以缩减到0.7秒:
for i = 1, 1000000 do
    local a = {true, true, true}
    a[1] = 1; a[2] = 2; a[3] = 3
end
复制代码

  3. 如果以正整数作为key存储的key,与索引重复,则以索引的值为准

  4. 可以用任意类型当表的key, 除了nil, 和布尔类型

复制代码
--表的赋值
local a = "b"
local table1 = {["false"] = 123,["nil"] = 456,a = 10,[a] = 20}
print(table1["false"]) --输出结果: 123
print(table1["nil"])   --输出结果: 456
print(table1.a)  --输出结果: 10
print(table1[a]) --输出结果: 20
print(table1["b"])   --输出结果: 20
print(table1[b])   --输出结果: nil
print("任意类型做键值, 除nil和布尔类型")
--任意类型做键值, 除nil和布尔类型
local t = {}
local f = function() end
local tbl = {[t] = 123, [f] = 456}
print(tbl[t])       --输出结果: 123
print(tbl[f])       --输出结果: 456
复制代码

 

三. table指针

  1.  当我们为 table a 设置元素,然后将 a 赋值给 b,则 a 与 b 都指向同一个内存。如果 a 设置为 nil ,则 b 同样能访问 table 的元素。如果没有指定的变量指向a,Lua的垃圾回收机制会清理相对应的内存

复制代码
local tbl = {}          --定义并初始化一个空表
local tab = tbl         --将tbl保存的地址赋值tab
tab["name"] = "名字"    --设置tab表中字段的值
--因为两个变量都指向同一个地址(表), 改变tab表中字段的值, tbl也会跟着改变
print(tbl.name)    --输出tbl表中字段的值, 输出结果: 名字

tbl = nil          --将tbl的值设置为nil
--因为上面设置的是tbl的值, 而tab还是指向了表的地址
print(tab.name)    --输出结果: 名字
复制代码

四. table中存在nil的注意事项

  1. #获取数组的长度, 遇到nil会立即停止计数, 而导致无法正确取得 table 的长度

local t = {1,nil,2,nil,nil}
print(#t)           --输出结果为: 1

--解决办法:将nil赋值一个字符串nil或者用""当空
local t = {1,"nil",2,"nil","nil"}
print(#t)           --输出结果为: 5

 五. lua表的实现方式

  1. 一般情况下不需要了解表的实现方式就能够使用它, 但是了解一些表的实现细节可以更好的掌握性能的开销情况

  2. Lua表的内部包含两个部分:数组部分和哈希部分

local t = {1,2,3}--保存在数组部分
local t = {[1] = 1, [2] = 2, [3] = 3}    --保存在hash部分
--"#"可以获取数组的长度, 也可以获取hash部分数字字段的长度

  3. 重新哈希的原理

 

复制代码
例子: 
    --这种写法要比下面的写法在性能上要快, 因为在开始时, 就确定了数组的大小, 不超过这个大小不会重新哈希
    local t = {true, true, true, true, true}    
    --------------------------------------------------
    local t = {}    --当Lua创建空表时,两个部分的大小都是0
    t[1] = true     --触发一次重新哈希, 将数组部分设置为2^0, 哈希部分是0
    t[2] = true     --触发一次重新哈希, 将数组部分设置为2^1, ...
    t[3] = true     --触发一次重新哈希, 将数字部分设置为2^2, ...
    t[4] = true     --不会触发重新哈希, 重新哈希则只会发生在表完全填满后
    t[5] = true     --触发一次重新哈希, 将数组部分设置为2^3, ...  重新哈希时, 都会创建原本大小的2倍
    
    结论:
    对于大的表来说,初期的几次重新哈希的开销被分摊到整个表的创建过程中
    一个包含三个元素的表需要三次重新哈希,而一个有一百万个元素的表也只需要二十次。
    但是当创建几千个小表的时候,重新哈希带来的性能影响就会非常显著。
    
    Lua也会为哈希部分创建一个大小为4的数组。例如,执行下面的代码需要2.0秒
    for i = 1, 1000000 do
        local a = {}
        a[1] = 1; a[2] = 2; a[3] = 3
    end
    如果在创建表时给定正确的大小,执行时间可以缩减到0.7秒
    for i = 1, 1000000 do
        local a = {true, true, true}
        a[1] = 1; a[2] = 2; a[3] = 3
    end
复制代码

 

  4. 如果你遍历一个表并清除其所有项(也就是全部设为nil),表的大小不会缩小。但是此时,如果你需要插入新的元素,表的大小将会被调整。多数情况下这都不会成为问题,但是,不要指望能通过清除表项来回收内存:最好是直接把表自身清除掉。

六. table函数库

  1. table.concat()

 

复制代码
--[=[
    local str = table.concat (list [, sep [, i [, j]]])
    语法: 
        local str = table.concat (list [, sep [, i [, j]]])
    译文: 
        local 合成字符串 = table.concat (数组 [, 合成字符串后每个元素的分隔符 [, 开始位置 [, 结束位置]]])
    功能: 
        将数组中的第一维合并成字符串, 其所有元素都是字符串或数字, 否则合并会报错
    参数: 
        参数list(必选): 数组
        参数sep(可选): 合成字符串后每个元素的分隔符, 默认为""
        参数i(可选): 开始位置, 如果i>#list则返回空串, i > j 也返回空串, 默认值为:1
        参数j(可选): 结束位置, j的默认值是 #list
    返回值:
        返回合成后的字符串内容
--]=]
--[[
    lua中的每个字符串都是单独的一个拷贝,拼接两个字符串会产生一个新的拷贝
    如果拼接操作特别多,就会影响性能,所以对于密集型的字符并接,table.concat 比用 ".." 连接更高效。
--]]

--例子1: 
local t = {123,456,567,678}
print(table.concat(t,",",1,#t))     --输出结果: "123,456,567,678"

--例子2:
t = {1,2,3,nil,4}
--print(table.concat(t,",",1,#t))     --报错, 合并的数组元素必须是字符串或数字, 其它类型都会报错
复制代码

 

  2. table.move()

 

 

复制代码
--[=[
    table.move (a1, f, e, t [,a2])
    语法: 
        table.move (a1, f, e, t [,a2])
    译文: 
        table.move (a1, f, e, t [,a2])
    功能: 
        把表a1中从下标f到e的value移动到表a2中,位置为a2下标从t开始
    参数: 
        参数a1(必选): 被复制的数组或复制到的数组(取决于是否有a2参数)
        参数f(必选) : 复制开始位置
        参数e(必选) : 复制结束位置
        参数t(必选) : 接收的位置(从a2或a1中的第几个位置开始覆盖, 取决于是否有a2参数)
        参数a2(必选): 接收的数组, 如果有此参数, 则将复制的内容按照接收位置依次复制到此数组(a2)
                                  如果没有此参数, 则将复制的内容按照接收位置依次复制到a1数组
    返回值:
        无
--]=]

tbl = {"a","b","c"} 
newtbl = {1,2,3,5}
--将tbl表中的元素b,c复制到newtbl表中,从newtbl表中的第二个元素开始覆盖
table.move(tbl, 2, 3, 2, newtbl)
print(table.concat(tbl,",")) --输出结果:   a,b,c
print(table.concat(newtbl,",")) --输出结果: 1 b c 5

--将tbl表中的元素a,b,c复制到tbl表中(如果没有第二个table则会复制带自身),从第三个元素开始覆盖
table.move(tbl, 1, 3, 3)
print(table.concat(tbl,",")) --输出结果: a b a b c
复制代码

 

  3. table.soft()

 

复制代码
--[=[
    table.soft (arr, function)
    语法: 
        table.soft (arr, function)
    译文: 
        table.soft (arr, function)
    功能: 
        根据函数规则, 对arr数组进行排序
    参数: 
        参数arr(必选): 要排序的数组
        参数function(可选): 排序的规则, 为比较false时才会交换位置, 如果不填写默认为"<", 进行升序排序
                            当比较的两个元素相等的时候,比较函数一定要返回false,返回true会报错
                            table.sort会根据你返回的bool来判断两个value是否保持原来的顺序
    返回值:
        无
--]=]

--对数组进行排序
--例子1:
local t1 = {8,10,5,2,6}
--默认为"<", 进行升序排序
table.sort(t1)
print(table.concat(t1, "|"))

--例子2:
local t1 = {8,10,5,2,6}
--进行降序
table.sort(t1, function(a,b) return a > b end)
print(table.concat(t1, "|"))


--例子3:
local t1 = {
    {id = 1, num = 88, level = 30},
    {id = 2, num = 66, level = 10},
    {id = 3, num = 66, level = 90},
    {id = 4, num = 99, level = 20},
    {id = 5, num = 66, level = 90}
}
table.sort(t1, function(a, b) return a.num < b.num end)
for _, v in pairs(t1) do
    print(string.format("id = %d, num = %d, level = %d", v.id, v.num, v.level))
end


--例子4: 多个条件进行排序, 在排序中两个值相等必须返回的是false才不会报错
print("多个条件进行排序")
local t1 = {
    {id = 1, num = 88, level = 30},
    {id = 2, num = 66, level = 10},
    {id = 3, num = 66, level = 5},
    {id = 4, num = 99, level = 20},
    {id = 5, num = 66, level = 300}
}
table.sort(t1, function(a, b) --如果仅相等让他返回false, 这种写法也可以not (a.num >= b.num)
    if a.num < b.num then
        return true
    elseif a.num == b.num then
        return a.level < b.level
    elseif a.num > b.num then
        return false
    end
end)

for _, v in pairs(t1) do
    print(string.format("id = %d, num = %d, level = %d", v.id, v.num, v.level))
end

--例子5: 根据value排序key
print("value的大小排序key")
local tbl = {[1] = 40303, [3] = 40304, [5] = 40305, [7] = 40301, [9] = 40302}
local t = {1,3,5,7,9}
table.sort(t, function(a,b) return tbl[a] < tbl[b] end)
print(table.concat(t,"|"))
复制代码

 

  4. table.insert()

 

复制代码
--[=[
    table.insert (list, [pos,] value)
    语法: 
        table.insert (list, [pos,] value)
    译文: 
        table.insert (数组, [插入位置,] 插入值)
    功能: 
        在数组指定位置插入元素, 会将插入位置后的数组元素依次往后移
    参数: 
        参数list(必选): 插入元素的数组
        参数pos(可选): 插入数组的位置, 默认为: 末尾插入
        参数value(可选): 插入的数组元素(值)
    返回值:
        无
--]=]
--
--例子1:
local table1 = {"","Lua",""}
table.insert(table1,2,"")
print(table.concat(table1))        --输出结果: 学习Lua中
复制代码

 

  5. table.remove()

 

复制代码
--[=[
    table.remove (list [, pos])
    语法: 
        table.remove (list [, pos])
    译文: 
        table.remove (数组 [, 删除位置])
    功能: 
        删除数组中指定位置的元素, 会将删除位置后的数组元素往前移
    参数: 
        参数list(必选): 删除元素的数组
        参数pos(可选): 删除数组中元素的位置, 默认为: #list, 删除数组中的最后一个元素
    返回值:
        被移除的值
--]=]
--例子1:
local tbl = {"a", "b", "c", "d", "e"} 
local value = table.remove(tbl, 4)
print(value)                  --输出结果: d
print(table.concat(tbl,", ")) --输出结果: a, b, c, e

value = table.remove(tbl)
print(value)                  --输出结果:e
print(table.concat(tbl,", ")) --输出结果: a, b, c
复制代码

 

  6. table.pack()

 

复制代码
--[=[
    local arr = table.pack(...)
    语法: 
        local arr = table.pack(...)
    译文: 
        local 数组 = table.pack(列表)
    功能: 
        将列表打包成一个table, 其中包含一个字段 n,表示该表的长度
    参数: 
        可变长参数...(必选): 要打包的列表
    返回值:
        返回一个打包好的数组
--]=]

--例子1:
function table_pack(param, ...)
    local arg = table.pack(...)
    print(arg.n)
    for i = 1, arg.n do
        print(i, arg[i])
    end
end
table_pack("test", "param1", nil, "param3")
复制代码

 

  7. table.unpack()

 

复制代码
--[=[
    local list = table.unpack(arr)
    语法: 
        local list = table.unpack(arr)
    译文: 
        local 列表 = table.pack(数组)
    功能: 
        将数组解包成序列, 如果存在nil将中断解包, 然后返回
    参数: 
        参数arr(必选): 待解包的数组
    返回值:
        返回一个列表, (每个元素是一个返回值)
--]=]

--例子1:
print(table.unpack({1,2,3,nil,5,nil}))  --输出结果: 1   2   3
复制代码
posted @   小书臣  阅读(200)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 全程不用写代码,我用AI程序员写了一个飞机大战
· MongoDB 8.0这个新功能碉堡了,比商业数据库还牛
· 记一次.NET内存居高不下排查解决与启示
· DeepSeek 开源周回顾「GitHub 热点速览」
· 白话解读 Dapr 1.15:你的「微服务管家」又秀新绝活了
点击右上角即可分享
微信分享提示