Lua语言学习之table探索
来源:互联网 发布:天刀好看少女捏脸数据 编辑:程序博客网 时间:2024/05/29 21:17
前面已经初步认识了table,这次对table进行深入学习。
table类型实现了“关联数组(associative)”,它是一种具有特殊索引方式的数组,
不仅可以用整数来索引它,还可以使用字符串或其他类型的值(除了nil)来索引它。
此外,table没有固定的大小,可以动态地添加任意数量的元素到一个table中。
table是Lua中主要的(事实上也是仅有的)数据结构机制,具有强大的功能。
基于table,可以以一种简单、统一和高效的方式来表示普通数组、符号表(symbol table)、集合、记录、队列和其他数据结构。Lua也是通过table来表示模块(module)、包(package)和对象(object)的。当输入io.read的时候,
其含义是 ” io模块中的read函数 “。对Lua而言,这表示“ 使用字符串“ read "
作为key来索引 table io”。
1、table的构造式(constructor expression)
tab1 = {78, 45,8}tab2 = {x = 78, y = 45,z = 99}
tab1是用构造式初始化一个数组,tab2使用了Lua提供的一种特殊的语法用于
初始化记录风格的table,也可以将两种风格混合使用。
注意:
local a = {}x = "y"a[x] = 10print("a[x] = ", a[x]) --->10print("a.x = ", a.x) --->nilprint("a.y = ", a.y) --->10上面的代码中,a.x 和 a[x] 是有区别的:a.x 相当于 a["x"]
2、table的内存与长度操作
table永远是“匿名的(anonymous)”,一个持有table的变量与table自身之间
没有固定的关联性。当一个程序再也没有一个table的引用时,Lua的垃圾回收器(garbage collector)最终会删除该table,并复用它的内存。
a = {}a["x"] = 10b = a --->a与b引用了同一个tableprint(b["x"]) --->10b["x"] = 20print(a["x"]) --->10a = nil --->还有b在引用tableb = nil -->再也没有对table的引用了,gc会删除该table
和string的长度操作一样,用一个井号(#)就能得到table的长度:
-- 打印表 a 的所有元素for i = 1, #a doprint(a[i])end
print(a[#a]) --->打印a中的最后一个值a[#a] = nil--->删除a中的最后一个值</span>a[#a + 1] = v --->在尾部添加一个值</span>
注意:
1). 再次提醒Lua中的下标是从1开始的,但是你也可以让元素的下标从任意值开始。
2).Lua 5.0不支持长度操作符,可以使用函数table.getn来获得类似的结果。建议使用最新的Lua,
现在更新到 5.2 了。
3).Lua 将nil作为界定数组结尾的标志。所以,当数组中有空隙时(Hole,即有nil),长度操作符
会认为这些nil 元素就是结尾标记。
4). Lua 5.1 新加的一个函数table.maxn 可以返回一个table的最大正索引。
3、table实现的数据结构
1).数组,前面已经接触到数组了:
-- 新建一个数组a = {}for i = 1, 1000 do a[i] = 0end
也可以用多维数组来表示一个矩阵:
-- 初始化一个 N * M 的矩阵matrix = {}for i = 1, N domatrix[i] = {} for j = 1, M domatrix[i][j] = 0 endend
2).链表:链表中每个节点具有两个字段:指向下一个节点的next和当前节点
保存的值value。
head = nil--->表头head = { next = head, value = 90} --->在表头插入一个元素list1 = { next = list1, value = 91}head.next = list1list2 = { next = list2, value = 92}list1.next = list2local x = headwhile x doprint(x.value)x = x.nextend
3). 队列与双向队列:实现队列的一种简单方法是使用table库的函数 insert 和 remove。
这两个函数可以在一个数组的任意位置插入或删除元素,并且根据操作要求移动后续元素。
一种更高效的实现是使用两个索引,分别用于首尾的两个元素:
queue = {}function queue.new( )return { first = 0, last = -1}endfunction queue.pushFront(q, v)-- bodylocal first = q.first - 1q.first = firstq[first] = vendfunction queue.pushBack(q, v)-- bodylocal last = q.last + 1q.last = lastq[last] = vendfunction queue.popFirst(q)-- bodylocal first = q.firstif first > q.last thenerror("queue is empty")endlocal value = q[first]q[first] = nilq.first = first + 1return valueendfunction queue.popLast(q)-- bodylocal last = q.lastif q.first > last thenerror("queue is empty")endlocal value = q[last]q[last] = nilq.last = last - 1return valueend-- 打印队列元素function queue.travel(q)-- bodylocal first = q.firstif first > q.last thenerror("queue is empty")endwhile first < q.last dolocal value = q[first]print(value)first = first + 1endend
每个节点表示为一个table,这个table有两个字段:name和adj
(与此节点邻接的节点集合)。
-- 给定节点名称返回对应的节点local function name2node (graph, name)if not graph[name] thengraph[name] = { name = name, adj = {} }endreturn graph[name]end
-- 从文件中读取图数据function readgraph ()local = graph = { }for line in io.lines() dolocal namefrom, nameto = string.match(line, "(%S+(%S+)")local from = name2node(graph, namefrom)local to = name2node(graph, nameto)from.adj[to] = trueendreturn graphend
-- 使用深度优先遍历
function findpath(curr, to, path, visited)path = path or { }visited = visited or { }if visited[curr] thenreturn nilendvisited[curr] = truepath[#path + 1] = currif curr == to thenreturn pathend-- 尝试所有的邻接节点for node in pairs(curr.adj) dolocal p = findpath(node, to, path, visited)if p then return p endendpath[#path] = nil ---从路径中删除节点end
3、table内部的原理:元表(metatable)与元方法(metamethod)
元表与元方法是很重要的概念,后面会查找相关资料,做更详细的了解,
这里只是针对table中的元方法做简单介绍。
前面已经接触过,当访问table中不存在的key时就会返回一个nil,这是正常状况。
其实,table内部的访问机制是:当访问一个table中不存在的字段时,会促使
解释器去查找一个叫__index的元方法。如果没有这个元方法,那么访问的
结果就是nil,否则就由这个元方法来提供最终结果。对于添加元素,
也有一个类似的__newindex元方法。而这些方法是元表中提供的,所以
需要设置一个table的元表,用setmetatable函数即可。下面给出一个
带有默认值的table示例:
function setDefault (t, d)local mt = { __index = function () return d end }setmetatable(t, mt)end
tab = { x = 10, y = 12 }print( tab.x, tab.z ) ----->10 nilsetDefault( tab, 0 )print( tab.x, tab.z ) ---->10 0
3、table库:由一些辅助函数构成,这些函数将table作为数组来操作。
1). 插入与删除:
table.insert ( t, pos, value ) -->将元素(value)插入到一个数组(t)的指定位置(pos),
如果没有指定位置参数,则默认将元素添加到数组的末尾。一般,用 t[#t + 1] 来
给一个列表添加元素。
table.remove( t ,pos ) 会删除(并返回)数组指定位置上的元素,并将该位置
之后的所有元素前移,以填补空隙。如果不指定位置参数,默认会删除数组的
最后一个元素。对于数据量比较小时,用这些方法比较合适,数据量大时开销
就太高,需要用更高级的算法来实现相关操作。
2). 排序:table.sort( t, cmp ), 可以对一个数组进行排序,还可以指定一个可选
的次序函数cmp。此参数是一个外部函数, 可以用来自定义sort函数的排序标准.
此函数应满足以下条件: 接受两个参数(依次为a, b), 并返回一个布尔型的值,
当a应该排在b前面时, 返回true, 反之返回false.
例如, 当我们需要降序排序时, 可以这样写:
> sortFunc = function(a, b) return b < a end
> table.sort(tbl, sortFunc)
> print(table.concat(tbl, ", "))
------>gamma, delta, beta, alpha
用类似的原理还可以写出更加复杂的排序函数. 例如, 有一个table存有工会
三名成员的姓名及等级信息:
guild = {}
table.insert(guild, {
name = "Cladhaire",
class = "Rogue",
level = 70,
})
table.insert(guild, {
name = "Sagart",
class = "Priest",
level = 70,
})
table.insert(guild, {
name = "Mallaithe",
class = "Warlock",
level = 40,
})
对这个table进行排序时, 应用以下的规则: 按等级升序排序, 在等级相同时,
按姓名升序排序.
可以写出这样的排序函数:
function sortLevelNameAsc(a, b)
if a.level == b.level then
return a.name < b.name
else
return a.level < b.level
end
end
3). 连接:table.concat(table, sep, start, end)
concat是concatenate(连锁, 连接)的缩写. table.concat()函数列出参数中
指定table的数组部分从start位置到end位置的所有元素, 元素间以指定的
分隔符(sep)隔开。除了table外, 其他的参数都不是必须的, 分隔符的
默认值是空字符, start的默认值是1, end的默认值是数组部分的总长.
sep, start, end这三个参数是顺序读入的, 所以虽然它们都不是必须参数,
但如果要指定靠后的参数, 必须同时指定前面的参数.
> tbl = {"alpha", "beta", "gamma"}
> print(table.concat(tbl, ":"))
alpha:beta:gamma
> print(table.concat(tbl, nil, 1, 2))
alphabeta
> print(table.concat(tbl, "\n", 2, 3))
beta
gamma
更多方法,参见:http://www.cnblogs.com/whiteyun/archive/2009/08/10/1543139.html
- Lua语言学习之table探索
- Lua语言学习之函数探索
- lua之table学习
- lua语言学习九table
- Lua语言之table表
- lua学习之table类型
- lua学习之table类型
- lua学习之table类型
- Lua学习笔记之table
- lua学习之table类型
- lua学习笔记之table的遍历
- lua学习之table表排序
- lua学习笔记之浅淡table
- Lua语言中的table
- Lua语言学习之迭代器
- Lua语言学习之环境
- lua table源码学习
- Lua学习笔记--table
- android.view.WindowLeaked的解决方法
- Jquery 扩展方法
- java学习日记02
- 恒天云 3.0:打造基于OpenStack的私有云新模式
- Spring Web Flow 2 中流管理的持久化
- Lua语言学习之table探索
- Android中WebView与Javascript交互的问题
- toString方法的调用
- Unity 相关经典博客资源总结(持续更新)
- 2440驱动程序设备节点创建
- Qwt源码解读之标尺相关类——日期时间标尺绘制类QwtDateScaleDraw
- http-关于application/x-www-form-urlencoded等字符编码的解释说明
- 解决手机访问网站时整体相对屏幕缩小问题?(已解决)
- 计划读一读FreeBSD的源代码