【Lua 筆記】表(table) - part 9 === 目錄(Table of Contents): [TOC] --- 由於有款遊戲叫做 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(表) | 菜鸟教程](https://www.runoob.com/lua/lua-tables.html) ```lua= -- 初始化 table mytable = {} -- 在 table 中指定值 mytable[1]= "Lua" -- 移除引用 mytable = nil -- lua 垃圾回收會自動釋放記憶體 ``` (程式語言有個概念是:資料通常都被存放在記憶體當中) > 當我們為 table a 並設定元素,然後將 a 賦值給 b,則 a 與 b 都指向同一個記憶體位址。如果 a 設定為 nil,則 b 同樣能存取 table 的元素。如果沒有指定的變數指向 a,Lua 的垃圾回收機制會清理相對應的記憶體。 以下是個範例: ```lua= mytable = {} print("mytable 的型態是 ", type(mytable)) mytable[1]= "Lua" mytable["wow"] = "修改前" print("mytable 索引為 1 的元素是 ", mytable[1]) print("mytable 索引為 wow 的元素是 ", mytable["wow"]) -- alternatetable 和 mytable 都是同一個 table alternatetable = mytable print("alternatetable 索引為 1 的元素是 ", alternatetable[1]) print("alternatetable 索引為 wow 的元素是 ", alternatetable["wow"]) alternatetable["wow"] = "修改後" print("mytable 索引為 wow 的元素是 ", mytable["wow"]) -- 釋放變數 alternatetable = nil print("alternatetable 是 ", alternatetable) -- mytable 仍然可以被存取 print("mytable 索引為 wow 的元素是 ", mytable["wow"]) mytable = nil print("mytable 是 ", mytable) ``` 輸出結果: ``` mytable 的型態是 table mytable 索引為 1 的元素是 Lua mytable 索引為 wow 的元素是 修改前 alternatetable 索引為 1 的元素是 Lua alternatetable 索引為 wow 的元素是 修改前 mytable 索引為 wow 的元素是 修改後 alternatetable 是 nil mytable 索引為 wow 的元素是 修改後 mytable 是 nil ``` 以下是筆者自創範例,主要說明最上面的五項(動態性、鍵值對等): ```lua= -- 空 table local myTable = {} -- 動態新增 items myTable[1] = "Lua" myTable[2] = 42 myTable["key"] = "value" myTable[3] = function() return "Hello, World!" end -- 刪除 items myTable[2] = nil -- 顯示 table 的內容 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 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(表) | 菜鸟教程](https://www.runoob.com/lua/lua-tables.html) | 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 進行升序排序。 | 以下是個範例: ```lua= -- 自訂 table.maxn 函數(Lua 5.2 之後已不存在) 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 在指定位置插入元素 table.insert(fruits, 2, "orange") print("After insert: " .. table.concat(fruits, ", ")) -- table.maxn 找出 table 中最大的正數 key 值 local maxKey = table.maxn(fruits) print("Max key: " .. maxKey) -- table.remove 刪除指定位置的元素 local removedFruit = table.remove(fruits, 3) print("Removed fruit: " .. removedFruit) print("After remove: " .. table.concat(fruits, ", ")) -- table.sort 對 table 進行排序 table.sort(fruits) print("After sort: " .. table.concat(fruits, ", ")) -- table.concat 將 table 轉換為字串 local fruitString = table.concat(fruits, ", ") print("Concatenated string: " .. fruitString) ``` 輸出結果: ``` 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 降序排序 --- ```lua= local fruits = {"apple", "banana", "cherry"} -- table.sort 對 table 進行降序排序 table.sort(fruits, function(a, b) return a > b end) print("After sort (descending): " .. table.concat(fruits, ", ")) ``` 輸出結果: ``` 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 的大小。 ### 基本操作 --- ```lua= -- 初始化 table mytable = {} -- 在 table 中指定值 mytable[1] = "Lua" mytable["key"] = "value" -- 移除引用 mytable = nil ``` ### 表(table)方法 --- 1. table.concat:將 table 的元素連接成字串。 2. table.insert:在指定位置插入元素。 3. table.maxn:找出 table 中最大的正數 key 值(Lua 5.2 之後已不存在)。 4. table.remove:刪除指定位置的元素。 5. table.sort:對 table 進行排序。 ```lua= local fruits = {"apple", "banana", "cherry"} -- 插入元素 table.insert(fruits, 2, "orange") -- 找出最大 key 值 local maxKey = table.maxn(fruits) -- 刪除元素 local removedFruit = table.remove(fruits, 3) -- 排序 table.sort(fruits) -- 轉換為字串 local fruitString = table.concat(fruits, ", ") ``` ### 降序排序 --- ```lua= local fruits = {"apple", "banana", "cherry"} table.sort(fruits, function(a, b) return a > b end) ``` 參考資料 --- [Lua | Tables | Codecademy](https://www.codecademy.com/resources/docs/lua/tables) [【30天Lua重拾筆記20】基礎3: 複合結構 - table | 又LAG隨性筆記](https://www.lagagain.com/post/30%E5%A4%A9lua%E9%87%8D%E6%8B%BE%E7%AD%86%E8%A8%9820%E8%A4%87%E5%90%88%E7%B5%90%E6%A7%8B-table/) [Lua table(表) | 菜鸟教程](https://www.runoob.com/lua/lua-tables.html)