1. 程式人生 > 其它 >lua基本語法之table操作

lua基本語法之table操作

Lua中table內部實際採用雜湊表和陣列分別儲存鍵值對、普通值;下標從1開始

不推薦混合使用這兩種賦值方式。

local color={first="red", "blue", third="green", "yellow"}

print(color["first"])                 --> output: red
print(color[1])                       --> output: blue
print(color["third"])                 --> output: green
print(color[2])                       --> output: yellow
print(color[3])                       --> output: nil

一)table.getn 獲取長度

相關於取長度操作符寫作一元操作 #。

字串的長度是它的位元組數(就是以一個字元一個位元組計算的字串長度)。
對於常規的陣列,裡面從 1 到 n 放著一些非空的值的時候,它的長度就精確的為 n,即最後一個值的下標。

local tblTest1 = { 1, a = 2, 3 }
print("Test1 " .. table.getn(tblTest1))

此table的長度為2,可是明明是三個數值啊,這裡要說明一下,getn 只能執行數值型的table,即數值索引的值.
忽略雜湊值型別的鍵值對map,即不包含字元索引值

local tblTest1 = { b=1, a = 2, 3 }
print("Test1 " .. table.getn(tblTest1))    #輸出長度為1

local tblTest1 = { b=1, a = 2, c=3 }
print("Test1 " .. table.getn(tblTest1))    #輸出長度為0

local tblTest1 = { 1, 2, 3 }
print("Test1 " .. table.getn(tblTest1))    #輸出長度為3

在有個地方說明一下
--此table 雖然有[3]=6,也是陣列型,但是不連續的,缺少了2的索引,所以輸出長度為1

local tblTest1 = { [3] = 6,c = 1, a = 2, [1]=3 }
print("Test1 " .. table.getn(tblTest1))   

--此table 數值索引是連續 到2,所以輸出長度為2
local tblTest1 = { [2] = 6,c = 1, a = 2, 3 } 
print("Test1 " .. table.getn(tblTest1))   

=============================
獲取table長度,不區分陣列和鍵值對

function table_length(t)
  local leng=0
  for k, v in pairs(t) do
    leng=leng+1
  end
  return leng;
end

=================
特殊說明:

如果陣列有一個“空洞”(就是說,nil 值被夾在非空值之間),那麼 #t 可能是指向任何一個是 nil 值的前一個位置的下標(就是說,任何一個 nil 值都有可能被當成陣列的結束)。
這也就說明對於有“空洞”的情況,table 的長度存在一定的 不可確定性。

關於nil的特別說明
local tblTest2 = { 1,nil,2}
對一個table中有nil值 取長度,會有很多不確定性,不同的luajit版本輸出的結果也不一樣

不要在 Lua 的 table 中使用 nil 值,如果一個元素要刪除,直接 remove,不要用 nil 去代替。

二)table.concat (table [, sep [, i [, j ] ] ])

對於元素是 string 或者 number 型別的表 table,
返回 table[i]..sep..table[i+1] ··· sep..table[j] 連線成的字串。填充字串 sep 預設為空白字串。
起始索引位置 i 預設為 1,結束索引位置 j 預設是 table 的長度。如果 i 大於 j,返回一個空字串。

local a = {1, 3, 5, "hello" }
print(table.concat(a))              -- output: 135hello
print(table.concat(a, "|"))         -- output: 1|3|5|hello
print(table.concat(a, " ", 2, 4))   -- output: 3 5 hello
print(table.concat(a, " ", 4, 2))   -- output:

在介紹string字串那邊有個字串拼接,是用.. 這個符號進行的

local str = "a" .. "b" .. "c"..........................  推薦用concat

三)table.insert (table, [pos ,] value)

在(陣列型)表 table 的 pos 索引位置插入 value,其它元素向後移動到空的地方。
pos 的預設值是表的長度加一,即預設是插在表的最後。

local a = {1, 8}             --a[1] = 1,a[2] = 8
table.insert(a, 1, 3)   --在表索引為1處插入3
print(a[1], a[2], a[3])
table.insert(a, 10)    --在表的最後插入10
print(a[1], a[2], a[3], a[4])

-->output
3   1   8
3   1   8   10

四)table.remove (table [, pos])

在表 table 中刪除索引為 pos(pos 只能是 number型)的元素,並返回這個被刪除的元素,
它後面所有元素的索引值都會減一。pos 的預設值是表的長度,即預設是刪除表的最後一個元素。

local a = { 1, 2, 3, 4}
print(table.remove(a, 1)) --刪除速索引為1的元素
print(a[1], a[2], a[3], a[4])

print(table.remove(a))   --刪除最後一個元素
print(a[1], a[2], a[3], a[4])

-->output
1
2   3   4   nil
4
2   3   nil nil

五)table.sort (table [, comp])

local a = { 1, 7, 3, 4, 25}
table.sort(a)           --預設從小到大排序

print(a[1], a[2], a[3], a[4], a[5])
-->output
1   3   4   7   25

按照給定的比較函式 comp 給表 table 排序,也就是從 table[1] 到 table[n],這裡 n 表示 table 的長度。
比較函式有兩個引數,如果希望第一個引數排在第二個的前面,就應該返回 true,否則返回 false。
如果比較函式 comp 沒有給出,預設從小到大排序。

local function compare(x, y) --從大到小排序
   return x > y         --如果第一個引數大於第二個就返回true,否則返回false
end

table.sort(a, compare) --使用比較函式進行排序
print(a[1], a[2], a[3], a[4], a[5])

-->output
25  7   4   3   1

六)table.maxn (table)

返回(陣列型)表 table 的最大索引編號;如果此表沒有正的索引編號,返回 0。

local a = {}
a[-1] = 10
print(table.maxn(a))
a[5] = 10
print(table.maxn(a))

-->output
0
5

七)table 判斷是否為空

大家在使用 Lua 的時候,一定會遇到不少和 nil 有關的坑吧。
有時候不小心引用了一個沒有賦值的變數,這時它的值預設為 nil。如果對一個 nil 進行索引的話,會導致異常。
如下:

local person = {name = "Bob", sex = "M"}
-- do something
person = nil
-- do something
print(person.name)

報錯person為nil了
然而,在實際的工程程式碼中,我們很難這麼輕易地發現我們引用了 nil 變數。
因此,在很多情況下我們在訪問一些 table 型變數時,需要先判斷該變數是否為 nil,例如將上面的程式碼改成:

local person = {name = "Bob", sex = "M"}
-- do something
person = nil
-- do something
if person ~= nil then
  print(person.name)
else
  print("person 為空")
end

對於簡單型別的變數,我們可以用if (var == nil) then這樣的簡單句子來判斷。
我們如果要判斷table型別的物件是否為空,那如何判斷呢?

我們思考一下,判斷table是否為空有兩種情況:

第一種table物件為nil;
第二種table物件為{},代表沒有鍵值對,但不為nil。

那麼我們一般的判斷邏輯就應該是 table == nil 或者 table的長度為0 就表示為空
下面我們看看以下例子:

local a = {}
local b = {name = "Bob", sex = "Male"}
local c = {"Male", "Female"}
local d = nil

if a == nil then
    print("a == nil")
end

if b == nil then
    print("b == nil")
end

if c == nil then
    print("c == nil")
end

if d== nil then
    print("d == nil")
end
 
if next(a) == nil then
    print("next(a) == nil")
end

if next(b) == nil then
    print("next(b) == nil")
end

if next(c) == nil then
    print("next(c) == nil")
end

以上有幾個注意點,涉及到table型別的長度
(#a) --"#"表示為獲取table型別的長度,類似table.getn()
因為a為{},所以長度為0.

我們再看(#b) ,依然輸出的是0,但b是有值的啊。

我們再看(#c),輸出的是2,這個是怎麼回事。這裡就是之前在table型別的課程中已經介紹的獲取table的長度,
只是獲取的是 陣列型的長度,不包含map型的。

我們再往下看 if a == nil then 在判斷 a是否為nil,明顯a不為nil
if next(a) == nil then中的next是什麼意思呢?

next (table [, index])
功能:允許程式遍歷表中的每一個欄位,返回下一索引和該索引的值。
引數:table:要遍歷的表
   index:要返回的索引的前一索中的號,當index為nil[]時,將返回第一個索引的值,
當索引號為最後一個索引或表為空時將返回nil
next(a) 就是返回第一個索引的值,a的第一個索引是沒有值的,那麼next(a) 就為nil
所以next方法經常用來判斷 table中是否有值。
下面的語句相信大家就能看懂了。
綜合以上程式碼,我們判斷table是否為空,就不能簡單的判斷table長度是否為0,而是判斷索引值。

所以要判斷table是否為空應該按照以下進行判斷

function isTableEmpty(t)
    return t == nil or next(t) == nil
end

八)ipairs和pairs的區別

為了看出兩者的區別,首先定義一個table:

a={"Hello","World";a=1,b=2,z=3,x=10,y=20;"Good","Bye"}  
for i, v in ipairs(a) do
	print(v)
end

輸出的結果是:

Hello
World
Good
Bye

可見ipairs並不會輸出table中儲存的鍵值對,會跳過鍵值對,然後按順序輸出table中的值。
再使用pairs對其進行遍歷:

for i, v in pairs(a) do
	print(v)
end

輸出的結果是:

Hello 
World 
Good  
Bye   
1     
10    
2     
20    
3     

可見pairs會輸出table中的值和鍵值對,並且在輸出的過程中先按順序輸出值,再亂序輸出鍵值對。
這是因為table在儲存值的時候是按照順序的,但是在儲存鍵值對的時候是按照鍵的雜湊值儲存的,
並不會按照鍵的字母順序或是數字順序儲存。
對於a來說,如果執行print(a[3]),輸出的結果也會是Good。也就是說table並不會給鍵值對一個索引值。

也就是說ipairs只是按照索引值順序,打印出了table中有索引值的資料,沒有索引值的不管。
而pairs是先按照陣列索引值列印,列印完成後再按照雜湊鍵值對的鍵的雜湊值列印它的值。

LuaJIT 2.1 新增加的 table.new 和 table.clear 函式是非常有用的。
前者主要用來預分配 Lua table 空間,後者主要用來高效的釋放 table 空間,並且它們都是可以被 JIT 編譯的。