TCL --- 列表_part1
0 回顾
列表part0详细介绍了列表的创建和修改。很多场景下,我们只需要获取列表中的元素;查找列表中是否存在某个元素;对列表中的元素进行升序或者降序的排列。
1 取值
需要获取列表中元素的内容,随后用于逻辑判断,这显然是非常常见的场景之一。Tcl提供了lindex命令获取列表的元素。
-
lindex命令格式
lindex list0 index0
lindex需要两个参数,分别是列表和索引值;最终返回列表中获取的“元素”。其中,“元素”可以是元素或者是子列表。请注意list0表示的是列表,并不是列表的变量名称。 -
基础示例
# 创建列表x_list set x_list [list John Anne Mary Jim] # 查找列表x_list中index=1的元素 lindex $x_list 1 # 结果:Anne # 查找倒数第2个元素 lindex $x_list end-1 # 结果:Mary #查找最后一个元素 lindex $x_list end # 结果:Jim # 创建列表y_list set y_list [list a b {c d e} f] # 查找列表y_list中index 2中的子列表 lindex $y_list 2 # 结果:{c d e} lindex $y_list 2 0 # 结果:c lindex $y_list 2 2 # 结果:e # 查找超出范围,返回空字符串 lindex $y_list 4 # 结果: 空字符
-
解析
x_list Jone Anne Mary Jim index 0 1 2 3 队列的index从0开始算,通常最后一个index用end表示,或者通过llength获取列表的长度,然后-1,便可获得最后一个元素,但此方法不过简洁。推荐使用end。
列表的嵌套在实际使用中较为常见。为此我们提供了第2中类别的示例。目的是为了展示列表嵌套的情况下是如何查找列表的元素。如列表y_list中的子列表{c d e}。从列表的角度来看,子列表也存在index。如子列表{c d e}对应的下标分别是0 1 2。下表中的sub_index表示子列表的index。从另一个角度来理解,列表张的所有元素都是一个子列表,只是该子列表中使用一个元素。因此,sub_index为0。当然,这种理解是不严谨的。x_list a b {c d e} f index 0 1 2 3 sub_index 0 0 0 1 2 0 子列表的嵌套示例说明了Tcl中的列表是支持层级嵌套的。通过index一层一层的往内部查找。如:
lindex $y_list index0 index1 index2 index3
index0表示第一个层级的查找;index1表示第2个层级的查找;index2表示第3个层级的查找;index3表示第4个层级的查找。
在比较两个队列是否相同时,若开始就按个比较两个队列的所有元素,显然不是明智之举。我认为第一步应该是比较队列的长度。若两个队列的长队都不一样,那就没有必要按个比较队列的元素了。Tcl提供llength命令用于获取列表的长度。
-
llength命令格式
llength list0
该命令需要一个参数,该参数可以是一个列表,也可以是一个元素;返回的结果是列表的长度。如前文提到的,单个元素可以理解为列表的大小为1,即只包含一个元素的列表。 -
基础示例
# 创建列表x_list set x_list [list [a b c d]] # 获取列表的长度 llength $x_list 结果:4 创建元素y_element set y_element 1 llength $y_element # 结果:1 # 创建列表y_list set y_list [list a b {c d e} f] # 获取列表y_list的长度 llength $y_list # 结果: 4
-
解析
x_list a b c d index 0 1 2 3 x_list中包含了4个元素。因此,返回的结果为4;
y_list a b {c d e} f index 0 1 2 3 y_list中第一层仍旧包含了4个元素。因此,返回的结果为4。从列表y_list的第一层来看,子列表仍旧是第一层的一个元素,只是这个元素是子列表。
假设我们需要把列表中的元素分别赋值给多个变量。最容易想到的方案应该是:
- 获取列表的长度,即采用llength
- 采用for循环,循环的次数为llength
- 采用lindex分别获取列表中每个index对应的元素
- 通过lindex获取的元素赋值变量
方案虽然简单,但是步骤繁琐。Tcl提供lassign命令实现该功能。
- lassign命令格式
lassign list0 var_name0 var_name1 var_name2
该命令可以方便的将列表中的值分发到一个或者多个变量中。list0表示列表而不是列表名;var_name0/1/2表示变量名。若变量名多余列表中的元素,则多余的变量被设置为空字符串;若列表中的元素比变量个数多,则返回一个由未分发的元素组成的列表。 - 基础示例
# 创建列表var_list0 set var_list0 [list a b c] # 把列表var_list0中的元素分发给变量X,变量Y以及变量Z lassign $var_list X Y Z puts "$X $Y $Z" # 结果:X=a; Y=b; Z=c# 创建列表var_list1 set var_list1 [list f g h i] X Y lassign $var_lsit X Y puts "$X $Y" # 结果:X=f; Y=g; 命令行返回剩下的元素h和元素i# 创建列表var_list2 set var_list2 [list d e] lassign $var_list2 X Y Z puts "$X $Y $Z" # 结果: X=d; Y=e; Z=NA; # NA表示空字符串
- 解析
常见的使用场景,lassign的列表可以是Tcl预定的列表argv,我么可以直接将命令行(terminal)传递的参数赋值给Tcl脚本的内部参数。如:
lassign $argv var_a var_b var_c
2 搜索
Tcl提供了两种查找元素是否存在列表中的命令。它们分别是lsearch,in和ni。其中,in和ni可以认为是同一个命令。下文将详细的介绍它们。
-
lsearch命令格式
lsearch list0 element0
该命令用于获取元素element0在列表中list0的索引下标,默认情况下是查找第一个匹配的元素。若元素element0不存在于列表list0中,则返回的结果是-1;否则返回对应的索引下标。即index。list0表示列表,而不是列表的名字;element0表示待搜索的元素。 -
基础示例
# 创建列表x_list set x_list [list John Anne Mary Jim] # 在x_list中搜索元素Mary对应的index lsearch $x_list Mary # 结果:2# 在x_list中搜索元素Phil对应的index lsearch $x_list Phil # 结果: -1, 即元素Phil不存在于列表x_list中
-
解析
上述的俩个示例给人的感觉就是lsearch这个命令不好用,甚至觉得非常的鸡肋。用户首先需要知道列表中包含哪些元素,只有这样才能正确的返回对应的index。日常使用中通常是不知道列表是否包含某个元素。因此,使用这个命令经常会得到-1。
显然lsearch不会如此简单。lsearch命令是可以携带参数的。如携带-glob,-regexp,-exact,-all,-inline。Option Description -glob 根据string match命令的规则进行匹配。string match后期或专门出一篇文章进行介绍 -regexp 根据正则表达式的规则进行匹配 -exact 严格匹配方式,并且区分大小写,不推荐使用 -not 根据规则匹配好之后取反 -all 查找出所有符合匹配规则的元素 -inline 使得lsearch命令返回元素本身,而不是元素对应的index 针对表格的选项给出以下示例
# 创建列表x_list set x_list [list California Hawaii Iowa Maine Vermont] # -glob匹配字符a结尾的元素, 仅匹配第一个符合要求的元素 lsearch -glob $x_list *a # 结果:0# -glob匹配所有字符a结尾的元素 lsearch -all -glob $x_list *a # 结果:0 2# -regexp匹配所有字符a结尾的元素 lsearch -regexp $x_list *a # 结果:0 2# -exact严格匹配 lsearch -exact $x_list Hawaii # 结果: 1# -not 取反; glob匹配所有非字符a结尾的元素 lsearch -not -glob $x_list *a # 结果:1 3 4# -line 输出所有匹配成功元素本身,而不是index lsearch -inline -all $x_list *a # 结果: California Iowa
-
in命令格式
element0 in list0
元素element0属于列表list0。若属于列表list0,则返回1;若不属于列表list0,则返回0。通常用于if条件判断,在条件判断中建议采用字符串或者变量的形式(if条件判断会在后续的文章中介绍) -
基础示例
# 创建列表x_list set x_list [list California Hawaii Iowa Maine Vermont] # Hawaii必须是字符串,否则Tcl将认为是一个变量,若之前没有定义,则报错,即使没有报错也可能不符合咱们的设计意图。因此,若不是变量则需要指明未字符串。 if {"Hawaii" in $x_list} {puts "Yes" } else {puts "No" } # 结果: Yes
-
解析
用于判断元素是否存在于列表中。它和lsearch -exact可有等效实现。如if {[lsearch -exact $x_lsit "Hawaii"] != -1} {puts "Yes" } else {puts "No" } # 结果: Yes }
-
ni命令格式
它是in命令取反。即,若元素存在于列表中,则返回0;否则返回1。因此,不在赘述。