本文會以vector / map / set 這三種數據類型的角度來梳理 table 支持的不同遍歷方式。
table as std::vector
一般,C/C++中的 array / vector (下文簡稱 vector) 是沒有 key。但是在 lua 中使用了 table 這種通用結構,就引入了 key 的問題。
在這里,把想用做 vector 的 table,做一個非常重要的約定:1 初始,key 連續。由於 table 的自由度很高,這個需要開發者自己約束。
---- 新建
t = {"A", "BB", "CCC"} -- 默認的key就是1初始且連續 -- 或者 t = {} -- 建立一個空的 t[1] = 1 t[2] = 2 t[3] = 3 -- 或者 t = { [1] = 1, [2] = 2, [3] = 3, -- 這里逗號可有可無 }
---- 模擬 pushback
vector = {} function vector.pushback(vec, val) vec[#vec + 1] = val end v = {} vector.pushback(v, 1) vector.pushback(v, 2) vector.pushback(v, 3)
---- 遍歷,使用 ipairs,按照key從1開始,從小到大返回元素。
for key, value in ipairs(v) do print(key, value) end
table as std::map 用key尋值,無重復。 通用情況
---- 新建
m = {["A"] = 1, ["BB"] = 2, ["CCC"] = 3} m = {["A"] = 1, ["BB"] = "string2", 10 = 3} -- key 和 value 的數據類型不必相同,自由伴隨着控制的難度,一定程度上,key 和 value 推薦使用相同的類型。value 也可以是 table。handle 這種情況需要注意更多。 -- 或者 m = {} -- 建立一個空的 m[1] = 1 m[2] = 2 m["3"] = 3 -- 打印結果和 3 一樣,可以通過 type 判斷類型差別。詳見后續例子 -- 或者 m = { [1] = 1, [2] = 2, ["3"] = 3, -- 這里逗號可有可無 }
---- 模擬 insert,不會重復插入
map = {} function map.insert(map, key, val) map[key] = val end m = {["A"] = "str1"} map.insert(m, 1, 25) map.insert(m, "1", 5) map.insert(m, 1, 2) map.insert(m, 1, 25)
---- 查詢元素,有就是1,沒有就是0
function map.have(map, key) if map[key] == nil then return false else return true end end m = {["A"] = "str1"} map.insert(m, 1, 25) map.insert(m, "1", 5) map.insert(m, 1, 2) map.insert(m, 1, 25) print(map.have(m, "A")) print(map.have(m, A)) ------- 結果 -------- true false
----遍歷,使用 pairs(),按照 key 的 harsh 值大小排序輸出。注意,順序這個概念在 map 中並不重要
for key, value in pairs(m) do print(key, type(key), value, type(value)) end
table as std::map 特殊情況:key 為數字,但不連續,希望從小到大遍歷,或相反。
使用迭代器(自定義的)
-- from: program in Lua function pairsByKeys(t) local a = {} for n in pairs(t) do a[#a + 1] = n end table.sort(a) -- 默認升序 -- table.sort(a, function(a1, a2) return a1 > a2 end) -- 降序 local i = 0 return function () i = i + 1 return a[i], t[a[i]] end end
完整示例:
map = {} function map.insert(map, key, val) map[key] = val end function map.have(map, key) if map[key] == nil then return false else return true end end -- from: program in Lua function pairsByKeys(t) local a = {} for n in pairs(t) do a[#a + 1] = n end table.sort(a) local i = 0 return function () i = i + 1 return a[i], t[a[i]] end end m = {} map.insert(m, 1, 10) map.insert(m, 3, 30) map.insert(m, 9, 90) map.insert(m, 5, 50) print("pairsByKeys") for key, value in pairsByKeys(m) do print(key, value) end print("pairs") for key, value in pairs(m) do print(key, value) end ----------- 結果 ------------ pairsByKeys 1 10 3 30 5 50 9 90 pairs 1 10 9 90 5 50 3 30
table as std::set 有序、不重復
這里的 map 和 set 的差別就是在插入的時候,需要對所有數據按照 key 排序,從小到大。在lua 里,map 已經沒有重復的 key。
---- 新建
s = {} s = {1,2,3} s = {"A", "B", "C"} --> 字符串排序的規則需要自己定義
---- 模擬 insert,需要指定 value 的比較方式。set 是升序排列的,key 值不可改(注意賦值方式),所以需要指定 value 的比較方式。
set = {} function set.insert(_s, val, _f) -- _f 就是需要自定義的比較函數,作為外部參數輸入。詳見后續 _s[#_s + 1] = val if #_s > 1 then table.sort(_s, _f) end end
---- 判斷元素有無
set = {} function set.have(s, key) if s[key] == nil then return false else return true end end
---- 迭代所有元素使用:ipairs()
for key, value in ipairs(s) do print(key, value) end
---- 完整示例
set = {} function set.insert(_s, val, _f) _s[#_s + 1] = val if #_s > 1 then table.sort(_s, _f) end end function set.have(s, key) if s[key] == nil then return false else return true end end -- you need to define a function to sort values in ascending order. function f(currenyVal, nextVal) return currenyVal < nextVal -- number end s = {} set.insert(s, 1, f) set.insert(s, 3, f) set.insert(s, 9, f) set.insert(s, 5, f) print(set.have(s, 10)) -- 判斷有無 print(set.have(s, 1)) for key, value in ipairs(s) do print(key, value) end
table as linked lists
請參考:https://www.lua.org/pil/11.3.html
table as queues (隊列,先進先出,不做介紹,請參考原文)
請參考:https://www.lua.org/pil/11.4.html
參考
http://blog.51cto.com/rangercyh/1032925
https://www.lua.org/pil/11.html