Huli's Blog

Learning by sharing

[Lua] Table使用手冊

| Comments

在lua裡面有個很重要的東西叫做table,是個非常好用的東西
有多好用呢?
這篇就來介紹一下一些table的用法

第一,它可以當做陣列來用

local t = {2,3,5,7,11,13,17,19}

print(t[3]) --5


--印出所有元素

for i = 1,#t do
    print(t[i].." ")
end

要注意的是lua的第一個index是1而不像某些程式語言(java、C)是0
#table_name是取得陣列長度的意思

如果你想要一個二維陣列,那也很方便

local t = {
    {1,1,1},
  {2,2,2},
  {3,3,3}
}

print(t[2][2]) --2

print(t[3][1]) --3

不像C/C++必須先定義好陣列長度,lua的table長度是可以隨時變動的
要加入一個元素你有幾種方法可以用

local t = {}
t[1]=2
t[#t+1]=3
table.insert(t,4)
--t = {2,3,4}

table.insert還可以指定要從table的哪個位置插入
例如說table.insert(t,1,4)就會在table的開頭插入4這個元素
原本在index 1的元素則會被推到index 2,往後的元素也都以此類推

雖然你可以把table當做純粹的陣列使用,但是table能做的事情多更多!
例如說,他可以當做C++裡面的map來使用,也就是使用字串當做索引值

local t = {
    ["a"] = "apple",
  ["b"] = "baby",
  ["c"] = "cool"
}
print(t["a"]) --apple

除了可以這樣子用以外,你也可以換一種表示方法

local t = {
    a = "apple",
    b = "baby",
    c = "cool"
}

print(t["a"]) --apple

除了使用t["a"]以外,你還可以用t.a來達成同樣的目的
像是

local peter = {
    name = "peter",
    height = 180
}
print(peter.height) --180

也可以嘗試更複雜的使用

local family = {
    sister={
        name="Lisa"   
    },
    father={
        name="nick"   
    },
    mother={
        name="Elsa"
    }
}

print(family.sister.name) --Lisa

print(family["father"]["name"]) -- nick

前面有講過如何遍歷一個陣列,而如果要遍歷像是這樣的table也很簡單

local family = {
    sister={
        name="Lisa"   
    },
    father={
        name="nick"   
    },
    mother={
        name="Elsa"
    }
}

for key,value in pairs(family) do
    print(key,value.name) 
    --sister   Lisa

    --mother   Elsa

    --father   nick

end

key就是table的索引值,而value就是那個索引值裡面的東西
例如說上面的例子,取代的value就會是{name=..}這個東西,所以要用value.name把名字取出來

pairs是lua提供的一個函式,除了pairs以外還有一個很相似的ipairs

local t = {
    10,20,30
}

for key,value in ipairs(t) do
    print(key,value) 
  -- 1 10

  -- 2 20

  -- 3 30

end

ipairspairs的差異,看幾個例子就知道了

local t = {
    a=100,10,20,[5]=30
}

for key,value in ipairs(t) do
    print(key,value) 
    --1 10

    --2 20

end

在上面這個範例中,t[a]=100,t[1]=10,t[2]=20,t[5]=30
ipairs會從index為1開始取,發現有t[1]所以繼續執行,發現有t[2]所以也繼續
但是當取到t[3]時發現沒有這個東西,於是就跳出了
所以可以知道ipairs會「順序性」的取出index為「數字」的值
而一旦中間斷掉了就不會再繼續(以上面的例子來說,沒有t[3]跟t[4])

pairs呢?

local t = {
    a=100,10,20,[5]=30
}

for key,value in pairs(t) do
    print(key,value) 
    --1 10

    --2 20

    --a 100

    --5 30

end

pairs會把table裡面的每一組資料都取出來
這就是pairsipairs的差異

接著要介紹幾個lua提供的好用的table方法
前面已經有介紹過table.insert
還有相似的table.remove

local t={1,3,5,7,9}
table.remove(t,3)

for i,v in ipairs(t) do
    print(i,v)
    --1 1

    --2 3

    --3 7

    --4 9

end

table.remove(t,3)的3代表的是index為3的元素,所以會把index為3的"5"這個元素刪除,後面的則會遞補上來

接下來還有table.concat,功能就跟javascript裡面的join差不多,就是用某個指定的字串把陣列串接起來

local t={1,3,5,7,9}

print(table.concat(t,"!"))
--1!3!5!7!9

最後還有很方便的table.sort

local t = {2,3,1,5,4}
table.sort(t)
print(table.concat( t,",")) 
-- 1,2,3,4 5

而你也可以使用table.sort(t,compare_function)傳入自己定義的函式,就會照著你的定義去排序
例如說你想要由大排到小

local t = {2,3,1,5,4}
local function compare(a,b)
    return a>b
end
table.sort(t,compare)
print(table.concat( t,",")) 
-- 5,4,3,2,1

或是你想讓偶數排在前面,如果一樣是偶數的話由小到大排

local t = {2,3,1,5,4}
local function compare(a,b)
    if(a%2==b%2) then
        return a<b
    else
        return a%2<b%2
    end
end
table.sort(t,compare)
print(table.concat( t,",")) 
-- 2,4,1,3,5

最後以一個實際上會用到table的例子做為這篇文章的總結
在Corona SDK中,我想建立一些按鈕,而我一開始是這樣寫的

local start_button = widget.newButton{
    left = 100,top = 200,id = "start",
    label = "start",onEvent = handleButtonEvent
}

local game_button = widget.newButton{
    left = 300,top = 400,id = "game",
    label = "game",onEvent = handleButtonEvent
}

local end_button = widget.newButton{
    left = 500,top = 400,id = "end",
    label = "end",onEvent = handleButtonEvent
}

local pause_button = widget.newButton{
    left = 600,top = 400,id = "pause",
    label = "pause",onEvent = handleButtonEvent
}

一共有四個按鈕,但是這樣寫十分冗長,而且如果我要新增/修改都很不方便
於是我就改用table來做這件事

local button_data = {
    {id="start",left=100,top=500,label="start"},
    {id="game",left=300,top=400,label="game"},
    {id="end",left=500,top=400,label="end"},
    {id="pause",left=600,top=500,label="pause"}
}

local buttons = {}

for i=1,#button_data do
    local btn=button_data[i]
    buttons[i] = widget.newButton{
        id=btn.id,label=btn.label,
        left=btn.left,top=btn.top,
        onEvent = handleButtonEvent
    }
end

這樣子不覺得版面簡潔很多嗎?

table真的是個很好用而且很方便的東西。

參考資料:
Tables Tutorial
Programming in Lua - Tables

Comments

comments powered by Disqus