【Lua 筆記】表(table) - part 9 由於有款遊戲叫做 CSO(Counter-Strike Online),內建模式創世者模式(Studio)新增使用 Lua 及其遊戲的 API,所以突發奇想製作這個筆記。
這個筆記會在一開始先著重純粹的程式設計自學,在最後的章節才會與 CSO 遊戲 API 進行應用。
表(Table) Lua 中的表(table)是一種很強很好用的資料結構,主要有以下幾個特點:
Dynamic :table 可以動態地新增或刪除項目(item),無需事先宣告 table 的大小。這讓 table 非常靈活,可以用於各種資料結構,如陣列、字典等。Key / Value(鍵值對) :table 中的資料是以鍵值對的形式進行儲存的。鍵(key)可以是任意型態的值(除了 nil),包括數字、字串或者 table 本身等。值(value)也可以是任意型態的。Difference :表中可以同時儲存不同型態的值,表示在同一個 table 中可以同時有整數、字串、函數等不同型態的資料。Index :Lua 中的 table 索引(index)可以是整數或者字串,這讓 table 既可以作為陣列使用,也可以作為字典(或稱哈希表、映射)使用。當使用整數作為索引時,表現形式和功能類似於傳統的陣列。Automatically Adjusting Size :當資料被新增到 table 當中時,Lua 會自動調整 table 的大小。總之 table 要說像是 python 當中的字典,好像也不完全是,因為他可以變來變去的,非常靈活。
table 格式 以下節錄自:Lua table(表) | 菜鸟教程
1 2 3 4 5 6 7 8 9 mytable = {} mytable[1 ]= "Lua" mytable = nil
(程式語言有個概念是:資料通常都被存放在記憶體當中)
當我們為 table a 並設定元素,然後將 a 賦值給 b,則 a 與 b 都指向同一個記憶體位址。如果 a 設定為 nil,則 b 同樣能存取 table 的元素。如果沒有指定的變數指向 a,Lua 的垃圾回收機制會清理相對應的記憶體。
以下是個範例:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 mytable = {} print ("mytable 的型態是 " , type (mytable))mytable[1 ]= "Lua" mytable["wow" ] = "修改前" print ("mytable 索引為 1 的元素是 " , mytable[1 ])print ("mytable 索引為 wow 的元素是 " , mytable["wow" ])alternatetable = mytable print ("alternatetable 索引為 1 的元素是 " , alternatetable[1 ])print ("alternatetable 索引為 wow 的元素是 " , alternatetable["wow" ])alternatetable["wow" ] = "修改後" print ("mytable 索引為 wow 的元素是 " , mytable["wow" ])alternatetable = nil print ("alternatetable 是 " , alternatetable)print ("mytable 索引為 wow 的元素是 " , mytable["wow" ])mytable = nil print ("mytable 是 " , mytable)
輸出結果:
1 2 3 4 5 6 7 8 9 mytable 的型態是 table mytable 索引為 1 的元素是 Lua mytable 索引為 wow 的元素是 修改前 alternatetable 索引為 1 的元素是 Lua alternatetable 索引為 wow 的元素是 修改前 mytable 索引為 wow 的元素是 修改後 alternatetable 是 nil mytable 索引為 wow 的元素是 修改後 mytable 是 nil
以下是筆者自創範例,主要說明最上面的五項(動態性、鍵值對等):
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 local myTable = {}myTable[1 ] = "Lua" myTable[2 ] = 42 myTable["key" ] = "value" myTable[3 ] = function () return "Hello, World!" end myTable[2 ] = nil for k, v in pairs (myTable) do print (k, v) end local arrayTable = {10 , 20 , 30 , 40 , 50 }for i = 1 , #arrayTable do print ("arrayTable[" .. i .. "] = " .. arrayTable[i]) end local dictTable = { name = "John" , age = 30 , occupation = "Developer" } for k, v in pairs (dictTable) do print (k .. ": " .. v) end table .insert (myTable, "New Item" )print ("After inserting a new item:" )for k, v in pairs (myTable) do print (k, v) end
輸出結果:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 1 Lua 3 function: 0x874f00 key value arrayTable[1] = 10 arrayTable[2] = 20 arrayTable[3] = 30 arrayTable[4] = 40 arrayTable[5] = 50 name: John occupation: Developer age: 30 After inserting a new item: 1 Lua 3 function: 0x874f00 4 New Item key value
:::info 之前我們說過,迭代一個陣列值用 ipairs 函數,或是用像是陣列值的 table。
而像字典(或不是字典也可以)這類的 table 則用 pairs。 :::
表(table)Method 表格來源:Lua table(表) | 菜鸟教程
Number 方法&用途 1 table.concat (table [, sep [, start [, end]]]):concat 是 concatenate(連鎖、連接)的縮寫。table.concat() 函數列出參數中指定 table 的陣列部分從 start 位置到 end 位置的所有元素,元素間以指定的分隔符號(sep)隔開。 2 table.insert (table, [pos,] value):在 table 的陣列部分指定位置(pos)插入值為 value 的一個元素。pos 參數可選(optional),預設為陣列部分結束。 3 table.maxn (table):指定 table 中所有正數 key 值中最大的 key 值。如果不存在key值為正數的元素,則回傳 0。(Lua5.2 之後此方法已經不存在了,本文使用了自訂函數實作) 4 table.remove (table [, pos]):回傳 table 陣列部分位於 pos 位置的元素。其後的元素會被前移。pos 參數可選,預設為 table 長度,即從最後一個元素刪起。 5 table.sort (table [, comp]):對給定的 table 進行升序排序。
以下是個範例:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 function table.maxn (t) local max = 0 for k, v in pairs (t) do if type (k) == "number" and k > max then max = k end end return max end local fruits = {"apple" , "banana" , "cherry" }table .insert (fruits, 2 , "orange" )print ("After insert: " .. table .concat (fruits, ", " ))local maxKey = table .maxn (fruits)print ("Max key: " .. maxKey)local removedFruit = table .remove (fruits, 3 )print ("Removed fruit: " .. removedFruit)print ("After remove: " .. table .concat (fruits, ", " ))table .sort (fruits)print ("After sort: " .. table .concat (fruits, ", " ))local fruitString = table .concat (fruits, ", " )print ("Concatenated string: " .. fruitString)
輸出結果:
1 2 3 4 5 6 After insert: apple, orange, banana, cherry Max key: 4 Removed fruit: banana After remove: apple, orange, cherry After sort: apple, cherry, orange Concatenated string: apple, cherry, orange
table.sort 降序排序 1 2 3 4 5 local fruits = {"apple" , "banana" , "cherry" }table .sort (fruits, function (a, b) return a > b end )print ("After sort (descending): " .. table .concat (fruits, ", " ))
輸出結果:
1 After sort (descending): cherry, banana, apple
:::info table.sort (table [, comp]),[, comp] 為比較函數的地方,在這邊使用一個匿名函數 function(a, b) return a > b end,這個函數會在排序過程中比較兩個元素,且在第一個元素大於第二個元素時回傳 true,從而實現降序(由大到小)排序。
匿名函數(Anonymous functions):沒有名稱的函數,通常架構較為簡略,大多情況能夠提升程式碼效率。補充:在 Python 則是用 lambda 作為匿名函數的關鍵字。 :::
總結 Dynamic:可以動態新增或刪除項目,無需事先宣告大小。 Key / Value:資料以鍵值對形式儲存,鍵和值可以是任意型態(除了 nil)。 Difference:同一個 table 中可以儲存不同型態的值。 Index:索引可以是整數或字串,既可作為陣列也可作為字典使用。 Automatically Adjusting Size:新增資料時,Lua 會自動調整 table 的大小。 基本操作 1 2 3 4 5 6 7 8 9 mytable = {} mytable[1 ] = "Lua" mytable["key" ] = "value" mytable = nil
表(table)方法 table.concat:將 table 的元素連接成字串。 table.insert:在指定位置插入元素。 table.maxn:找出 table 中最大的正數 key 值(Lua 5.2 之後已不存在)。 table.remove:刪除指定位置的元素。 table.sort:對 table 進行排序。 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 local fruits = {"apple" , "banana" , "cherry" }table .insert (fruits, 2 , "orange" )local maxKey = table .maxn (fruits)local removedFruit = table .remove (fruits, 3 )table .sort (fruits)local fruitString = table .concat (fruits, ", " )
降序排序 1 2 3 local fruits = {"apple" , "banana" , "cherry" }table .sort (fruits, function (a, b) return a > b end )
參考資料 Lua | Tables | Codecademy
【30天Lua重拾筆記20】基礎3: 複合結構 - table | 又LAG隨性筆記
Lua table(表) | 菜鸟教程