lua 的 table表 大小、元素个数 #操作 的体会【结论是错误的, 此后再更新】

有个体会, lua table 的 #操作 是针对 table.insert() / table.remove() 这一对操作的 “操作数维护”: 

每次调用 table.insert() 都会是 #操作值增加(这是我自己的表达, 即使 用 #table 取得表的 返回值);

每次调用 table.remove() 都会减少 #操作值。

 

table 内部元素维护 有两种方式:

第一种是 使用 table.insert() / table.remove() 这一对

第二种是 使用 operator[] 

 

另外, 采用默认值声明并定义表, 并且由positive key 时, lua引擎应该会“尝试”自动调用 table.insert() , 例如

local tb = { 11, 22, c33=33 }

我的假设过程是:

table.insert( tb, 11)

table.insert( tb, 22)

table.insert( tb, 33)

tb[ c33] = 33

 

有这么个假设 及 上述猜想后, 看如下例子:

local f = io.open( "out.out", "a" )

function trace( tb)
    f:write( "count of positive lements is ", #tb, "\n" )
    for k, v in pairs( tb) do 
        f:write( k, "\t", v, "\n")
    end
end

--=============================== create a table
local tb = { 11, 22, c33=33 }
trace( tb)

--=============================== insert positive number elements
for i = 1, 10, 1 do 
    table.insert( tb, i)
end
trace( tb)

--================================ add element with operator[]
tb[ 88] = 88
trace( tb)

--============================== remove elements with nil to operaor[]
for i = 1, 3, 1 do 
    tb[ i] = nil
end
trace( tb)

--============================== remove elements with table.remove()
for i = 1, 3, 1 do 
    table.remove( tb, 1)
end
trace( tb)

--=============================== add element with operator[]
tb[ 98] = 98
trace( tb)

f:write( table.maxn( tb) , "\n")
f:flush()
f:close()

输入结果将会是 out.out:

count of positive lements is 2
1    11
2    22
c33    33
count of positive lements is 12
1    11
2    22
3    1
4    2
5    3
6    4
7    5
8    6
9    7
10    8
11    9
12    10
c33    33
count of positive lements is 12
1    11
2    22
3    1
4    2
5    3
6    4
7    5
8    6
9    7
10    8
11    9
12    10
88    88
c33    33
count of positive lements is 12
4    2
5    3
6    4
7    5
8    6
9    7
10    8
11    9
12    10
88    88
c33    33
count of positive lements is 9
1    2
2    3
3    4
4    5
5    6
6    7
7    8
8    9
9    10
88    88
c33    33
count of positive lements is 9
1    2
2    3
3    4
4    5
5    6
6    7
7    8
8    9
9    10
88    88
98    98
c33    33
98

过程分析如下:

 

local f = io.open( "out.out", "a" )

function trace( tb)
    f:write( "count of positive lements is ", #tb, "\n" )
    for k, v in pairs( tb) do 
        f:write( k, "\t", v, "\n")
    end
end

--=============================== create a table
local tb = { 11, 22, c33=33 }
trace( tb) --[[ 按照上述假设 #操作值 为 2
count of positive lements is 2
1    11
2    22
c33    33

]]

--=============================== insert positive number elements
for i = 1, 10, 1 do 
    table.insert( tb, i)
end
trace( tb) --[[ 这里增加调用了 10次的 table.insert() 
count of positive lements is 12
1    11
2    22
3    1
4    2
5    3
6    4
7    5
8    6
9    7
10    8
11    9
12    10
c33    33

]]

--================================ add element with operator[]
tb[ 88] = 88
trace( tb) --[[ operator[] 维护表内元素, 并不会修改 #操作值
count of positive lements is 12
1    11
2    22
3    1
4    2
5    3
6    4
7    5
8    6
9    7
10    8
11    9
12    10
88    88
c33    33

]]

--============================== remove elements with nil to operaor[]
for i = 1, 3, 1 do 
    tb[ i] = nil
end
trace( tb) --[[ operator[] 维护表元素, 并不会修改 #操作值
count of positive lements is 12
4    2
5    3
6    4
7    5
8    6
9    7
10    8
11    9
12    10
88    88
c33    33

]]

--============================== remove elements with table.remove()
for i = 1, 3, 1 do 
    table.remove( tb, 1)
end
trace( tb) --[[ 3次 table.remove() 操作, 减少 #操作值
count of positive lements is 9
1    2
2    3
3    4
4    5
5    6
6    7
7    8
8    9
9    10
88    88
c33    33

]]

--=============================== add element with operator[]
tb[ 98] = 98
trace( tb) --[[ 又一次的 operator[] 操作, 并不会修改 #操作值
count of positive lements is 9
1    2
2    3
3    4
4    5
5    6
6    7
7    8
8    9
9    10
88    88
98    98
c33    33

]]

f:write( table.maxn( tb) , "\n") -- 98
f:flush()
f:close()

 

小结:

1.由于 lua table的元素的维护 分为 table.insert() / remove() 与 operator[] 两套实现机制, 在相对脚本语言, 尤其是项目多人协作、分时段开发时, 很容易产生 2*2 = 4中以上的 table表 元素维护方式, 容易造成混乱, 造成数据不安全问题。 是否应该对那些 涉及需要被 “多处”的 共享table 表 的操作进行 封装。

2.一个应用, 假如上述成立, 在新增数据时 统一用 table.insert() 带来简便, 并获取“流水号id”:

local tb = {}

function InsertTable( container, item )
    table.insert( container, item)
    item.seqno = #container
end

不然 直接的 operator[key] = item 得事先确定 key 值; 而在删除元素时, 不适用 table.remove() 而是用 operator[]:

--未考虑 nil 的key 判断

function RemoveByKey( container, key )
    container[ key] = nil
end

function RemoveByItem( container, item )
    container[ item.seqno] = nil
end

这样可保证在 container 的 #操作值 只递增, 是一个 “流水号”。

posted @ 2013-03-26 14:11  Wilson-Loo  阅读(27029)  评论(0编辑  收藏  举报