Lua笔记——2.表Table

table简介:

table是Lua中唯一的数据结构,其他语言所提供的数据结构如:arrays、lists、queues、sets等,Lua都是通过table来实现。

Array&Hash

在lua中通过整数下标访问table中元素,即是数组。并且数组大小不固定,可动态增长。

table的使用


    --file: testTable.lua
    --Description: 使用table创建数组
    tableArray = {}
    
    --使用默认索引,以及自定义key进行赋值
    --Notice:Lua的数组下标默认从1开始,当然可以根据需要从负值或者0作为下标开始
    --Lua的标准库遵循下标从1开始,因此你的数组下标必须也是从1开始,才可以使用标准库的函数
    tableArray = {"c","c++","c#","oc","java","kotlin",["s1"]= "python",["s2"]= "lua", ["s3"]= "javascript"}
    
    --使用默认索引对table内值进行修改
    tableArray[1] = "php"
    --使用自定义key值对table内值进行修改
    tableArray["s3"] = "js"
    --设置空值中断索引
    tableArray[5] = nil
    
    local getn = table.getn or
        function(t) 
            local len = 0 
            for k in ipairs(t) do 
                len = len + 1 
            end
            return len
        end
    
    local getnAll =function(t) 
            local len = 0 
            for k in pairs(t) do 
                len = len + 1 
            end
            return len
        end
    
    function ipairsPrint(table)
        --ipairs迭代器对索引升序遍历,索引中断遍历停止
        for k,v in ipairs(table) do
            print(k .. "---"..v)
        end
    end
    
    function pairsPrint(table)
        --pairs迭代器遍历所有非空元素
        for k,v in pairs(table) do
            print(k.."--"..v)
        end
    end
    
    ipairsPrint(tableArray)
    --lua5.1及之前版本的table.getn()方法,取得table中默认索引值的个数
    --lua5.1之后的使用自定义方法,只取得默认索引值元素的个数
    print("Array's index elements number : "..getn(tableArray))
    --lua5.1-5.3都适用的#table 取得table中默认索引值的个数
    print("Array's index number : " .. #tableArray)
    --自定义方法获取table的全部元素个数
    print("Array's all elemnets number : "..getnAll(tableArray).."\n")
    
    pairsPrint(tableArray)
    print("Array's index elements number : "..getn(tableArray))
    print("Array's index number : " .. #tableArray)
    print("Array's all elemnets number : "..getnAll(tableArray))

输出结果lua5.1,使用table.getn

y0xrvnD.png

输出结果lua5.3,使用自定义getn

4xTSK6v.png

总结:

  • Lua 内部采用数组和哈希表分别保存普通值和键值对,不推荐混合使用这两种赋值方式
  • lua5.3版本去掉了获取数组table中默认索引值个数的table.getn方法,但#table仍可以在不同版本中使用
  • 不要在 Lua 的 table 中使用 nil 值,如果要删除一个元素,应直接 remove,不要用 nil 去代替

table相关方法


    --file: testTabFunc.lua
    --Description: table's function
    tableArray = {"c","c++","c#","oc","java","kotlin",["s1"]= "python",["s2"]= "lua", ["s3"]= "javascript"}
    
    --字符串数组连接
    res1 = table.concat(tableArray)
    --给定字符串分隔符连接字符串数组元素
    res2 = table.concat(tableArray,"/")
    res3 = table.concat(tableArray,"/",2,6)
    
    print("table.concat(tableParam) :",res1)
    print("table.concat(tableParam,splitMark) :",res2)
    print("table.concat(tableParam,splitMark,startIndex,endIndex) :",res3)
    
    --给数组插入元素,无其他参数直接在末尾插入
    table.insert(tableArray,"swift")
    print("table.insert(tableParam,insertValue) :",table.concat(tableArray,"/"))
    
    table.insert(tableArray ,4,"go")
    print("table.insert(tableParam,insertValue,position) :",table.concat(tableArray,"/"))
    
    table.remove(tableArray,3)
    print("table.remove(tableParam,position) :",table.concat(tableArray,"/"))

Z3GMfxO.png

table相关问题

工作中会遇到接收到的数据有无效项,需要遍历table并且删除掉无效项的情况,在解决时当我们在table表中使用for迭代,将符合条件的元素删除之后,后面元素前移,然后产生跳跃——使用for i=1,#mytable 这样的循环时,由于在for时就已经确定了循环的终点是table的总索引长度,在整个for运行过程中,终点不会改变,以致于在循环到i = #mytable 时,会报错nil。

    --file: rmtable.lua
    
    t= {}
    
    for i = 1,10 do
        t[i] = i
    end
    
    function t.print()
        for i =1 ,#t do
            print(i..'-'..t[i])
        end
    end
    
    t.print()
    
    t[4] = nil
    t[7] = nil
    
    function t.check()
        local temp = {}
        for i = 1,#t do
            if t[i] then
                print(i.."-"..t[i])
            else
                table.remove(t,i)
                --Check the current value in i index , or while be error
                if t[i] then print(i.."-"..t[i]) end
            end
        end
    end
    
    --[[also can use the while loop]]
    -- function t.check()
    --  local i = 1 
    --  while i <= #t do
    --      if t[i] then
    --          print(i.."-"..t[i])
    --          i = i + 1
    --      else
    --          table.remove(t,i)
    --      end
    --  end
    -- end
    
    print("After check:")
    t.check()

1168371-20180325214130592-1966355701.png

Matrix

Lua中多维数组的表示方法:

数组的数组表示矩阵

Lua中矩阵的表示方法:一是“数组的数组”——table的每个元素是另一个table。


    --file: matrix.lua
    --creat a 4*3 matrix
    data = {}    
    
    --对数组元素赋值
    for i = 1,4 do
        data[i] = {}
        for j = 1 , 3 do
            data[i][j] = 0
        end
    end
    
    --输出数组元素
    for i =1 ,#data do 
        for j =1 ,#data[i] do
            print(data[i][j])
        end
    end

数组的下标表示矩阵

表示矩阵的另一方法,是将行和列组合起来。如果索引下标都是整数,通过第一个索引乘于一个常量(列)再加上第二个索引


    data = {}
    
    for i =0 ,3 do 
        for j = 0,2 do
            data[i*3 + j] = 0
        end
    end
    
    
    for i = 0 , #data do
        print(i..'-'..data[i])  
    end

linkedList

    --file: linkedList.lua
    
    list = nil    --链表的根节点
    
    for i = 1,10 do
        list = {next = list ,value = i}    --这样实现的Lua链表类似于C/C++中LIFO的链表
    end
    
    
    --遍历该链表
    local l = list 
    
    while l do
        print(l.value)
        l = l.next
    end

对Lua链表的具体理解可以参考本文末尾REF链接中stackoverflow中的相关问题

自定义链表的实现:

    --自定义链表类
    LList = {}
    
    LList.__index = LList
    
    
    
    function LList.create()
    
        local list = {} -- our new object
    
        setmetatable(list,LList) -- make LList handle lookup
    
        list.count = 0 -- initialize our object
    
        list.head = nil
    
        return list
    
    end
    
    
    
    function LList:add(newNode)
        print("DEBUG PRINT: LList:add(): newNode.data: "..newNode:getData().." LList.count: "..self.count)
    
        if(self.head) then
            local curr = self.head
            print("DEBUG PRINT: LList:add(): self.head:toString(): "..self.head:toString())
            print("DEBUG PRINT: LList:add(): curr:toString(): "..curr:toString())
            print("DEBUG PRINT: LList:add(): newNode:toString: "..newNode:toString())
    
            while curr.nextNode do --this is the while loop in question
                print("DEBUG PRINT: LList:add(): in while:"..curr:toString())
                curr = curr.nextNode
    
            end
    
            curr:setNext(newNode)
            print("DEBUG PRINT: LList:add(): curr.nextNode:toString(): "..curr.nextNode:toString())
    
            self.count = self.count + 1
        else
            self.head = newNode
    
            self.count = 1
            print("DEBUG PRINT: LList:add(): self.count" .. self.count .." self.head:getData(): ".. self.head:getData())
    
        end
        print("DEBUG PRINT: LList:add(): EXITING\n")
    
    end
    
    function LList:getLen()
        return self.count
    end
    
    function LList:toString()
    print("Stubbed toString()")
    if(self.head)then
        print(self:toStringHelper(self.head))
    else
        print("emptyList?")
        end
     end
    
    function LList:toStringHelper(currNode)
    
        if(currNode.nextNode)then
            return currNode:toString().. "\n" .. self:toStringHelper(currNode.nextNode)
            
        else
            return currNode:toString()
        end
    end
    
    -----------------------------------------------------------------------
    
    
    --Node类
    Node = {}
    
    Node.__index = Node
    
    
    
    function Node.create(newData)
    
        local tNode = {}
    --[[
        
        setmetatable(tNode, Node)
    
        tNode.data = newData
    
        return tNode
        
    --]]
    --以上代码可简写为:
        tNode.data = newData
        
        return setmetatable(tNode,Node)
        
    end
    
    function Node:getData()
        return self.data
    end
    
    function Node:getNext()
        return self.nextNode
    end
    
    function Node:setNext(newNode)
        self.nextNode = newNode
        print("DEBUG PRINT: Node:setNext(): self.nextNode:toString(): "..self.nextNode:toString())
    end
    
    function Node:hasNext()
        if self.nextNode then
            return true
        else
            return false
        end
    end
    
    function Node:toString()
        return tostring(self.data)
    end
    
    
    --测试代码:
    
    testerList = LList.create()
    print(testerList:getLen())
    
    tNode1=Node.create(5)
    tNode2=Node.create(7)
    tNode3=Node.create(2)
    
    testerList:add(tNode1)
    testerList:add(tNode2)
    testerList:add(tNode3)
    
    print(testerList:getLen())
    
    print(testerList:toString())

Queue

    --file: queue.lua
    
    list = {}
    
    function list.new()
        return {first = 0, last = -1}
    end
    
    function list.pushleft(list,value)
        local first = list.first -1
        list .first = first
        list[first] = value
    end
    
    function list.pushright(list , value)
        local last = list.last +1
        list.last = last
        list[last] = value
    end
    
    function list.popleft(list)
        local first = list.first
        
        if first > list.last then error("list is empty") end
    
        local value = list[first]
        list[first] = nil    --to allow garbage collection
        list.first = first+1
        return value
    end
    
    function list.popright(list)
        local last = list.last
        if list.first > last then error("list is empty") end
    
        local value = list[last]
    
        list[last] = nil    --to allow garbage collection
    
        list.last = last -1
        return value
    end
    
    function list.print(list)
        local point = list.last
        while list.first <= point do
            print(list[point])
            point = point -1
        end 
            
    end
    
    --The test code
    l = list.new()
    
    list.pushleft(l,1)  --list[-1] = 1
    list.pushright(l,2) --list[0] = 2
    list.pushleft(l,3)  --list[-2] = 3
    list.pushleft(l,4)  --list[-3] = 4
    list.pushright(l,5) --list[1] = 5
    
    --依次打印
    list.print(l)
    
    print("Test the queue's pop func:")
    --移除一个右边的和左边的
    print(list.popright(l)) -->5
    print(list.popleft(l))  -->4

1168371-20180325180955839-2008614691.png

Set

Lua中表示这个集合的简单方法:将所有集合中的元素作为下标存放在一个table里,只需要测试给定的元素在table对应下标的值是否为nil


    --file: set.lua
    
    Set = {}
    
    Set.mt = {}
    
    function Set.new(t)
        local set = {}
        for _,v in pairs(t) do
            set[v] = true
        end
        return setmetatable(set,Set.mt)
    end
    
    set1 = Set.new{1,2,3,4,5,}
    
    set2 = Set.new{4,5,6,7,8,}
    
    print("The same namber is :")
    
    for k in pairs(set1) do
        if set2[k] then
            print(k)
        end
    end

1168371-20180320204124613-1913486722.png

StringBuffer

Lua使用真正的垃圾收集算法,当发现程序使用太多的内存他就会遍历他所有的数据结构去释放垃圾数据,一般情况下,这个垃圾收集算法有着很好的性能——Lua的快并非偶然的

    --从一个文件中逐行读入字符串
    -- WARNING: bad code ahead!!
    local buff = ""
    for line in io.lines() do
        buff = buff .. line .. "\n"
    end

上面代码的循环使得该情况下Lua的垃圾回收算法的效率极其低下:

“为了理解现象的本质,假定我们身在loop中间,buff已经是一个50KB的字符串,每一行的大小为20bytes,当Lua执行buff..line.."\n"时,她创建了一个新的字符串大小为50,020 bytes,并且从buff中将50KB的字符串拷贝到新串中。也就是说,对于每一行,都要移动50KB的内存,并且越来越多。读取100行的时候(仅仅2KB),Lua已经移动了5MB的内存”——Programing in Lua

使情况变遭的是下面的赋值语句:

buff = buff .. line .. "\n"

“老的字符串变成了垃圾数据,两轮循环之后,将有两个老串包含超过100KB的垃圾数据。这个时候Lua会做出正确的决定,进行他的垃圾收集并释放100KB的内存。问题在于每两次循环Lua就要进行一次垃圾收集,读取整个文件需要进行200次垃圾收集。并且它的内存使用是整个文件大小的三倍。
这个问题并不是Lua特有的:其它的采用垃圾收集算法的并且字符串不可变的语言也都存在这个问题。Java是最著名的例子,Java专门提供StringBuffer来改善这种情况。”——Programing in Lua

解决方法:
“它连接两个小串成为一个稍微大的串,然后连接稍微大的串成更大的串。。。算法的核心是:用一个栈,在栈的底部用来保存已经生成的大的字符串,而小的串从栈定入栈。栈的状态变化和经典的汉诺塔问题类似:位于栈下面的串肯定比上面的长,只要一个较长的串入栈后比它下面的串长,就将两个串合并成一个新的更大的串,新生成的串继续与相邻的串比较如果长于底部的将继续进行合并,循环进行到没有串可以合并或者到达栈底。”——Programing in Lua


    function newStack ()
        return {""}   -- starts with an empty string
    end
     
     
    function addString (stack, s)
        table.insert(stack, s)   -- push 's' into the the stack
        for i=table.getn(stack)-1, 1, -1 do
           if string.len(stack[i]) > string.len(stack[i+1]) then
               break
           end
           stack[i] = stack[i] .. table.remove(stack)
        end
    end
    
    --使用
    local s = newStack()
    
    for line in io.lines() do
        addString(s, line .. "\n")
    end
    
    s = toString(s)
REF

http://book.luaer.cn/
http://www.lua.org/pil/contents.html
http://www.jb51.net/article/55717.htm
https://stackoverflow.com/questions/15708621/how-does-this-linked-list-example-in-lua-actually-work
https://stackoverflow.com/questions/21180601/lua-custom-linked-list-for-class-creation-practice-fails-to-set-node-next

转载于:https://www.cnblogs.com/sylvan/p/8478364.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值