Array VS Dict in Tcl
Tcl8.5开始引入了dict
,dict
与array
类似,都是处理键值对;但它们又有明显的差异。Tcl Array
虽然译为数组,但它其实不是数组,它存储的是变量;Tcl dict
可被视为Tcl list
,它存储的是值。
Tcl arrays are collections of variables;
Tcl dicts are pure values.
1. Tcl array
数组,是一种最基础的数据结构,是由相同类型的元素(element)的集合所组成的数据结构,分配一块连续的内存来存储。利用元素的索引(index)可以计算出该元素对应的存储地址。一般索引从0开始,一维数组的array[0]表示第一个元素,二维数组的array[0][0]表示第一个元素。所以我们这里说的数组其实是List
,一般的计算机语言里都会有list的结构,Tcl也不例外。List可以有不同的实现方法,比如java里就有arraylist
和linkedlist
(链表结构,存储位置不连续)。
而Tcl里的array
其实并不是数组
,它其实是一种键值对的数据结构(perl里称为hash,python里称为dict,java里称为map)。Tcl array存储的是变量,是一堆变量的集合。
Tcl array 写法简洁
Tcl array的读写很简洁,可以直接对arrayName(key)操作。eg:
1
2
3
4
5
% set arr(a) aaa
aaa
% puts $arr(a)
aaa
Tcl Array 与Tcl List 转化
可以将偶数个元素的Tcl List
直接通过array set
转化成Tcl Array
, Tcl Array
可以通过array get
返回一个key-var的Tcl List
。
1
2
3
% array set arr { a aaa b bbb }
% array get arr
a aaa b bbb
Tcl没有多维array
Tcl array的key是string,其实array不支持二维array,但可以用下面的方法来用,很像二维array。
1
2
3
4
5
6
% set arr(x1,y1) 11
11
% set arr(x1,y2) 12
12
% array name arr
x1,y2 x1,y1
如上所示,arr(x1,y1)
的key是x1,y1
,Tcl会把()
内的所有string当作key,甚至可以用下面这样来表示二维array,key值为x1)(y1
:
1
2
3
4
5
6
7
% array unset arr
% set arr(x1)(y1) 11
11
% set arr(x1)(y2) 12
12
% array name arr
x1)(y1 x1)(y2
Tcl array is unordered
Tcl array
是无序存储的,这也是其一大劣势。如果要按序取出的话,只能先把key按序存储到list里。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
% array unset arr
% array set arr {
a 11
c 33
d 44
b 22
}
% array name arr
d a b c
% array unset arr
% array set arr {
a 11
c 33
d 44
b 22
}
% array name arr
d a b c
2. Tcl Dict
Tcl Dict
是从8.5版才引入的,是高效的键值对操作方式。和array不同的是,dict存储的是值,其可被视为是Tcl list
,key有序存储,而且可以嵌套。
Dict is vaule
dict存储的是值,可以直接puts $dictName
来得到dict value,array是不可以的。
1
2
3
4
5
6
7
8
9
10
% set adict [dict create a 11 d 44 c 33 b 22]
a 11 d 44 c 33 b 22
% puts $adict
a 11 d 44 c 33 b 22
% array set arr {
a 11
b 22
}
puts $arr
cann't read “arr": variable is a array
Dict is a List
Tcl Dict
是有偶数个元素的list,每个奇数元素为key,其后的偶数元素为value。
1
2
3
4
5
6
7
8
9
10
11
% set alist {a 11 b 22 c 33 d 44}
a 11 b 22 c 33 d 44
% dict get $alist a
11
% dict get $alist b
22
### 奇数项list不能转化成dict
% set olist {a 11 b 22 c}
a 11 b 22 c
% dict get $olist a
missing value to go with ke
上面的例子中,定义了一个Tcl list alist
,随后直接对它dict cmd 操作。
Tcl Dict可以与Tcl List无损转化,由于dict底层是hash table实现,所以其性能还是与list有区别。
Internally, Tcl uses a hash table to implement a dictionary, so its performance characteristics are quite different from those of a plain list. To avoid the performance cost of shimmering, use only dict or ˇlistˇ commands to modify a dictionary.
The conversion between internal representations of a dictionary and a list is lossless. A round-trip conversion from dict to list and back again yields the original value.
Dict is ordered
既然dict可以和list相互转化,那dict自然也像list那样是有序的。
1
2
3
4
5
6
7
8
9
% set adict [dict create a 11 d 44 c 33 b 22]
a 11 d 44 c 33 b 22
% dict for {k v} $adict {
puts "$k: $v"
}
a: 11
d: 44
c: 33
b: 22
Dict can be nested
Dict存储的是值,它可以像list in list那样来嵌套使用
1
2
3
4
5
6
7
8
9
10
% set person {
lucy {age 20 sex female}
jake {age 25 sex male}
}
lucy {age 20 sex female}
jake {age 25 sex male}
% dict get [dict get $person lucy] age
20
也可用dict
cmd来嵌套,如下:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
% dict set person Lucy age 20
Lucy {age 20}
% dict set person Lucy sex female
Lucy {age 20 sex female}
% dict set person Jake age 25
Lucy {age 20 sex female} Jake {age 25}
% dict set person Jake sex male
Lucy {age 20 sex female} Jake {age 25 sex male}
% dict for {name info} $person {
puts "This is $name"
dict with info {
puts "age: $age"
puts "sex: $sex"
}
}
This is Lucy
age: 20
sex: female
This is Jake
age: 25
sex: male
Tcl dict
和Tcl array
的功能有重叠,我一般情况是优先用tcl array
,毕竟它的写法更简洁;如果需要按序或者嵌套,就用tcl dict
。