数组、列表和序列

简介: 数组、列表和序列

如果像表示常见的数组( array )或列表( list ),那么只需要使用整型作为索引的表即可。同时,也不需要预先声明表的大小,只需要直接初始化我们需要的元素即可:

a = {}
for i = 1, 10 do
  a[i] = io.read()
end


鉴于能够使用任意值对表进行索引,我们也可以使用任意数字作为第一个元素的索引。不过,在 Lua 语言中,数组索引按照惯例是从 1 开始的(不像很多语言从 0 开始), Lua 语言中的其他很多机制也遵循这个惯例。


当操作列表时,往往必须事先获取列表的长度。列表的长度可以存放在常量中,也可以存放在其他变量或数据结构中。通常,我们把列表的长度保存在表中某个非数值类型的字段中(由于历史原因,这个键通常是 "n" )。当然,列表的长度经常也是隐式的。


注意

未经初始化的元素均为 nil ,所以可以利用 nil 值来标记列表结束。


当向一个列表中写入了 10 行数据后,由于该列表的数值类型的索引为 1,2,...,10 ,所以可以很容易地知道列表的长度就是 10 。这种技巧只有在列表中不存在空洞hole )时(即所有元素均不为 nil )才有效,此时我们把这种所有元素都不为 nil 的列表称为序列sequence )。


Lua 语言提供了获取序列长度的操作符 # 。对于字符串而言,该操作符返回字符串的字节数;对于表而言,该操作符返回表对应序列的长度。例如,可以使用如下的代码输出上例中读入的内容:

for i = 1, #a do
  print(a[1])
end


长度操作符也为操作序列提供了集中有用的写法:

print(a[#a])      -- 输出序列'a'的最后一个值
a[#a] = nil       -- 移除最后一个值
a[#a + 1] = v     -- 把'v'加到序列的最后


对于中间存在空洞( nil 值)的列表而言,序列长度操作是不可靠的,它只能用于序列(所有元素均不为 nil 的列表)。更准确的说,序列sequence )是由指定的 n 个正整数值类型的键所组成集合 {1, ..., n} 形成的表(请注意值为 nil 的键实际不在表中)。特别的,不包含数值类型键的表就是长度为 0 的序列。


将长度操作符用于存在空洞的列表的行为是 Lua 语言中最具有争议的内容之一。在过去几年中,很多人建议在操作存在空洞的列表时直接抛出异常,也有人建议扩展长度操作符的语义。然而,这些建议都是说起来容易做起来难。其根源在于列表实际上是一个表,而对于表来说,“长度”的概念在一定程度上是不容易理解的。例如,考虑如下代码:

a = {}
a[1] = 1
a[2] = nil    -- 什么也没做,因为a[2]已经是nil了
a[3] = 1
a[4] = 1


我们可以很容易确定这是一个长度为 4 、在索引 2 的位置上存在空洞的列表。不过,对于下面这个类似的示例是否也是如此呢?

a = {}
a[1] = 1
a[10000] = 1


是否应该认为 a 是一个具有 10000 个元素、 9998 个空洞的列表?如果代码进行了如下的操作:

a[10000] = nil


那么列表的长度会变成多少?由于代码删除了最后一个元素,该列表的长度是不是变成了 9999 ?或者由于代码只是将最后一个元素变成了 nil ,该列表的长度仍然是 10000 ?又或者该列表的长度缩成了 1


另一种常见的建议是让#操作符返回表中全部元素的数量。虽然这种语义听起来清晰且定义明确,但并非非常特别有用和符合直觉。


思考

虽然这种语义听起来清晰且定义明确,但并非非常特别有用和符合直觉。为什么这么说?


更复杂的是列表以 nil 结尾的情况:

a = {10, 20, 30, nil, nil}


因为在 Lua 语言中,一个为 nil 的字段和一个不存在的元素没有区别,因此,上述列表与 {10, 20, 30} 是等价的——其长度是 3 而不是 5


可以将以 nil 结尾的列表当做一种非常特殊的情况。不过,很多列表是通过逐个添加各个元素创建出来的。任何按照这种方式构造出来的带有空洞的列表,其最后一定存在为 nil 的值。


尽管讨论了这么多,程序中的大多数列表其实都是序列(例如不能为 nil 的文件行)。正因为如此,在多数情况下使用长度操作符是安全的。在确实需要处理存在空洞的列表时,应该将列表的长度显式地保存起来。

目录
相关文章
|
3月前
|
算法 索引
LeetCode第34题在排序数组中查找元素的第一个和最后一个位置
这篇文章介绍了LeetCode第34题"在排序数组中查找元素的第一个和最后一个位置"的解题方法,通过使用双指针法从数组两端向中间同时查找目标值,有效地找到了目标值的首次和最后一次出现的索引位置。
LeetCode第34题在排序数组中查找元素的第一个和最后一个位置
|
6月前
|
存储 Python
使用元组创建列表并实现反转效果
使用元组创建列表并实现反转效果
31 1
|
6月前
在排序数组中查找元素的第一个和最后一个位置
在排序数组中查找元素的第一个和最后一个位置
|
6月前
|
算法 索引 Python
如何实现二分查找算法? 要求:编写一个Python函数,输入一个有序列表和一个目标值,返回目标值在列表中的索引。如果目标值不在列表中,返回-1。
如何实现二分查找算法? 要求:编写一个Python函数,输入一个有序列表和一个目标值,返回目标值在列表中的索引。如果目标值不在列表中,返回-1。
70 0
|
JavaScript Python
从列表中或数组中随机抽取固定数量的元素组成新的数组或列表
从列表中或数组中随机抽取固定数量的元素组成新的数组或列表
62 0
LeetCode-34 在排序数组中查找元素的第一个和最后一个位置
LeetCode-34 在排序数组中查找元素的第一个和最后一个位置
|
存储
返回集合中最大,最小的元素,再将元素进行排序
返回集合中最大,最小的元素,再将元素进行排序
58 0
|
算法 Python
一日一技:包含元组的列表,对第一个元素升序第二个元素降序
一日一技:包含元组的列表,对第一个元素升序第二个元素降序
99 0
【LeetCode】错误的集合&&在排序数组中查找元素的第一个和最后一个位置&&杨氏矩阵&&寻找数组的中心下标&&两个数组的交集
【LeetCode】错误的集合&&在排序数组中查找元素的第一个和最后一个位置&&杨氏矩阵&&寻找数组的中心下标&&两个数组的交集
【LeetCode】错误的集合&&在排序数组中查找元素的第一个和最后一个位置&&杨氏矩阵&&寻找数组的中心下标&&两个数组的交集
统计字符串中元素的个数(多种方法)
统计字符串中元素的个数(多种方法)
183 0
统计字符串中元素的个数(多种方法)