---
# System prepended metadata

title: 【Lua 筆記】表（table） - part 9
tags: [Lua, 程式語言]

---

【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)