您的位置:首页 > 编程语言 > Lua

Lua_第18 章 Table 库

2016-03-24 12:08 281 查看
第 18 章 Table 库

 

       table库由一些操作 table 的辅助函数组成。他的主要作用之一是对 Lua 中 array的大 小给出一个合理的解释。另外还提供了一些从 list 中插入删除元素的函数,以及对 array 元素排序函数。

 

18.1 数组大小

       Lua中我们经常假定 array 在最后一个非 nil 元素处结束。这个传统的约定有一个弊端:我们的 array 中不能拥有 nil 元素。对大部分应用来说这个限制不是什么问题,比如 当所有的 array 有国定的类型的时候。但有些时候我们的 array 需要拥有 nil 元素,这种情况下,我们需要一种方法来明确的表明 array 的大小。

      Table 库定义了两个函数操纵array 的大小:getn,返回 array 的大小;setn,设置 array 的大小。如前面我们所见到的,这两个方法和 table 的一个属性相关:要么我们在 table的一个域中保存这个属性,要么我们使用一个独立的(weak)table 来关联 table 和这个 属性。两种方法各有利弊,所以 table库使用了这两个方法。

      通常,调用 table.setn(t, n)使得 t 和 n 在内部(weak)table 关联,调用 table.getn(t)将得到内部 table 中和 t 关联的那个值。然而,如果表 t 有一个带有数字值 n 的域,setn 将修改这个值,而 getn 返回这个值。Getn 函数还有一个选择:如果他不能使用上述方法返回 array 的大小,就会使用原始的方法:遍历 array直到找到第一个 nil 元素。因此, 你可以在 array
中一直使用 table.getn(t)获得正确的结果。看例子:

 

print(table.getn{10,2,4})          -->3
print(table.getn{10,2,nil})        -->2
print(table.getn{10,2,nil; n=3})       -->3
print(table.getn{n=1000})                  -->1000

a = {}
print(table.getn(a))               -->0
table.setn(a, 10000)
print(table.getn(a))               -->10000

a ={n=10}
print(table.getn(a))               -->10
table.setn(a, 10000)
print(table.getn(a))               --> 10000


       默认的,setn 和 getn 使用内部表存储表的大小。这是最干净的选择,因为它不会使用额外的元素污染 array。然而,使用 n 域的方法也有一些优点。在带有可变参数的函数 种,Lua内核使用这种方法设置 arg 数组的大小,因为内核不依赖于库,他不能使用 setn。 另外一个好处在于:我们可以在 array  创建的时候直接初始化他的大小,如我们在上面例子中看到的。

     使用 setn 和 getn 操纵 array 的大小是个好的习惯,即使你知道大小在域 n 中。table库中的所有函数(sort、concat、insert 等等)都遵循这个习惯。实际上,提供 setn 用来改变域 n 的值可能只是为了与旧的 lua 版本兼容,这个特性可能在将来的版本中改变, 为了安全起见,不要假定依赖于这个特性。请一直使用 getn 获取数组大小,使用 setn 设 置数组大小。

 

18.2 插入/删除

      table 库提供了从一个 list 的任意位置插入和删除元素的函数。table.insert 函数在 array 指定位置插入一个元素,并将后面所有其他的元素后移。另外,insert 改变 array 的大小 (using  setn)。例如,如果 a 是一个数组{10,20,30},调用 table.insert(a,1,15)后,a变为{15,10,20,30}。经常使用的一个特殊情况是,我们不带位置参数调用
insert,将会在 array 最后位置插入元素(所以不需要元素移动)。下面的代码逐行独入程序,并将所有行保存 在一个 array 内:

a = {}
for line in io.lines() do
table.insert(a, line)
end
print(table.getn(a))        --> (number of linesread)

table.remove 函数删除数组中指定位置的元素,并返回这个元素,所有后面的元素前 移,并且数组的大小改变。不带位置参数调用的时候,他删除 array 的最后一个元素。

使用这两个函数,很容易实现枝、队列和双端队列。我们可以初始化结构为 a={}。 一个 push 操作等价于 table.insert(a,x);一个 pop 操作等价于 table.remove(a)。要在结构的另一端结尾插入元素我们使用 table.insert(a,1,x);删除元素用 table.remove(a,1)。最后两 个操作不是特别有效的,因为他们必须来回移动元素。然而,因为 table 库这些函数使用 C实现,对于小的数组(几百个元素)来说效率都不会有什么问题。

18.3 排序

       另一个有用的函数是 table.sort。他有两个参数:存放元素的 array 和排序函数。排序 函数有两个参数并且如果在 array 中排序后第一个参数在第二个参数前面,排序函数必 须返回 true。如果未提供排序函数,sort 使用默认的小于操作符进行比较。

       一个常见的错误是企图对表的下标域进行排序。在一个表中,所有下标组成一个集 合,但是无序的。如果你想对他们排序,必须将他们复制到一个 array 然后对这个 array排序。我们看个例子,假定上面的读取源文件并创建了一个表,这个表给出了源文件中 每一个函数被定义的地方的行号:

lines = {
luaH_set = 10,
luaH_get = 24,
luaH_present = 48,
}

       现在你想以字母顺序打印出这些函数名,如果你使用 pairs遍历这个表,函数名出现 的顺序将是随机的。然而,你不能直接排序他们,因为这些名字是表的key。当你将这 些函数名放到一个数组内,就可以对这个数组进行排序。首先,必须创建一个数组来保存这些函数名,然后排序他们,最后打印出结果:

a = {}
for n in pairs(lines) do table.insert(a, n) end
table.sort(a)
for i,n in ipairs(a) do print(n) end

       注意,对于 Lua 来说,数组也是无序的。但是我们知道怎样去计数,因此只要我们 使用排序好的下标访问数组就可以得到排好序的函数名。这就是为什么我们一直使用 ipairs 而不是 pairs 遍历数组的原因。前者使用key 的顺序 1、2、……,后者表的自然存 储顺序。

      有一个更好的解决方法,我们可以写一个迭代子来根据 key 值遍历这个表。一个可 选的参数 f可以指定排序的方式。首先,将排序的keys放到数组内,然后遍历这个数组,每一步从原始表中返回 key和 value:

 

function pairsByKeys (t, f)
local a = {}
for n in pairs(t) do table.insert(a, n) end
table.sort(a, f)
local i = 0                 -- iterator variable
local iter = function ()    -- iterator function
i = i + 1
if a[i] == nil then return nil
else return a[i], t[a[i]]
end
return iter
end

有了这个函数,很容易以字母顺序打印这些函数名,循环:

for name, line in pairsByKeys(lines) do
print(name, line)
end


打印结果:

luaH_get          24
luaH_present      48
luaH_set          10
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  lua