2016-11-05 33 views
4

假設我想存儲一個元素列表。包括一些零值。值的位置很重要,我需要在給定位置表示列表中沒有值。如何在表格中代表零

這裏是一個問題:

a = {1,2,3,nil,4} 

for k,v in ipairs(a) do 
    print(k,v) 
end 

print(a[4]) 
print(a[5]) 

for循環將只打印元件1,2和3。它停止在零。第一個打印語句輸出nil,但我不確定它是否實際存儲在表中。 (誰知道?)第二個打印語句按預期打印4。

所以,這裏是一個問題:如何表示一個表中的元素列表,並有效地遍歷它們?鑑於上述條件,例如這個職位很重要,有些職位是「空的」。換句話說:沒有價值,但是在那個位置沒有那個價值是有意義的。

回答

3

這是模塊「空」。LUA」

local function null(...) 
    local t, n = {...}, select('#', ...) 
    for k = 1, n do 
     local v = t[k] 
     if  v == null then t[k] = nil 
     elseif v == nil then t[k] = null 
     end 
    end 
    return (table.unpack or unpack)(t, 1, n) 
end 
_G.null = null 

使用null()作爲編碼器和解碼器

require("null") 

a = {null(1,2,3,nil,4)} 
-- the same could be done element-by-element 
-- a = {null(1),null(2),null(3),null(nil),null(4)} 

for k,v in ipairs(a) do 
    v = null(v) 
    print(k,v) 
end 

print(null(a[4])) 
print(null(a[5])) 
+0

我接受這個答案,因爲它使用本地表和本地ipairs,使用起來非常簡單,而且也很好地處理了真值測試。 – nagylzs

3

Lua表可以用來創建任何抽象數據結構,在你的情況下,你表明你想要一個「列表」。 Lua表是一種數據結構,它將基於數字索引的訪問與鍵值訪問相結合。

根據您的示例,您使用的表格的數字索引功能允許您通過這些值進行迭代(使用ipairs())。由於數字索引在第一個零輸入處停止,因此不能將零放入表中。表中剩餘的值存儲爲鍵:值對。

有幾種解決方法,但它取決於你爲什麼要在列表中爲零。最簡單的方法是使用字符串「nil」而不是本地數據類型nil。

a = {1, 2, 3, "nil", 4} 

for k,v in ipairs(a) do 
    print(k,v) 
end 

這段代碼的結果是:

1 1 
2 2 
3 3 
4 nil 
5 4 

的服務,因爲lua實現字符串的方式,沒有比較字符串「無」的性能損失相對比較原生型零。

數組中的「空洞」(由nil引起)的問題在Lua的第5章表格中進行了討論。 Roberto Ierusalimschy的建議是跟蹤陣列的大小以避免漏洞問題。

以下代碼顯示了一個面向對象的方法來跟蹤列表的大小。這個主題有很多可能的變化。

function makeList(...) 
    local list = table.pack(...) 

    list.length = 
    function(self) return self.n 
    end 

    list.append = 
    function(self, value) 
     self.n = self.n + 1 
     self[self.n] = value 
    end 

    list.print = 
    function(self) 
     for i = 1, self.n do print(i, self[i]) end 
    end 

    return list 
end 

a = makeList(1, 2, 3, nil, 4) 
a:append(5) 

a:print() 

print(a:length()) 

結果是:

1 1 
2 2 
3 3 
4 nil 
5 4 
6 5 
6 

注意函數table.pack創建包含項目的正確的號碼,即使「零」是存在的字段「N」。有關完整的解釋,請參見PIL第6.2章「變量函數」。

+3

通常的習慣用法是定義'null = {}'一次,並使用'null'而不是'nil'。 – lhf

+0

好的,這是一個解決方法。我明白我可以使用null或「nil」而不是零。但我認爲這是Lua的一個缺點。例如,如果我還需要測試元素的真值,那該怎麼辦?如果元素是通過函數調用返回的。然後我必須重構代碼並添加樣板代碼。這不是一個有效的方法。 – nagylzs

+0

我想我應該接受這個答案。我可以想出一個解決方法,它使用兩個表(一個用於鍵和一個用於值)。該結構本身可以使用零值。但這不是一個簡單而有效的方法。但似乎沒有本地解決方案,只有解決方法。 – nagylzs

1

不要一起破解一些東西,寫出你自己的數據結構。如果你「超負荷」 ipairs(通過寫適當的迭代器),你可以使用它作爲一個表:

function create(...) 
    local t = table.pack(...) 
    local self = { 
     num = t.n, 
     elements = { ... } 
    } 
    return self 
end 

function elements(t) 
    local f = function(s, i) 
     i = i + 1 
     if i <= s.num then 
      return i, s.elements[i] 
     end 
    end 
    return f, t, 0 
end 

local seq = create(1, 2, nil, 3) 

print(seq.num) 
for i, e in elements(seq) do 
    print(i, e) 
end 
-- results: 
-- 4 
-- 1 1 
-- 2 2 
-- 3 nil 
-- 4 3 

你可以知道定義該結構的元表,並用它自己的ipairs,讓你不甚至不得不改名。

1

這個問題的答案很簡單,而這些‘變通辦法’建議肯定是矯枉過正。就在不斷的項目數的軌道當你的表發生改變時(注意:不要使用#,你也要手動處理nil值),並使用數字循環遍歷它。

+1

我不認爲這是一個聰明的解決辦法「矯枉過正」。我總是更喜歡寫20行,而不是每次使用*時都要考慮使用結構。 – pschulz

0

那麼,你不能在nil中存儲nil表沒有問題。

這裏最簡單的解決方案是引入您自己獨特的價值。

local mynil = {} -- every new table is unique! 

a = {1,2,3,mynil,4} 

for k,v in ipairs(a) do 
    if (v == mynil) then 
    v = nil 
    end 
    print(k,v) 
end 

沒有更多的問題與「無」的字符串可能被存儲在表以及中,小問題是一個更比較。 ipairs或任何其他迭代器都會顯示值爲mynil的密鑰存在。這意味着您可以將mynil鍵存在與丟失鍵=nil分開。

P.S.如果你想改變你的名單,你可以考慮table.remove(list, key)函數。