2011-06-01 78 views
3

问题是我在数组中的“插入”元素的顺序在脚本的执行过程中发生了变化。如何确保TCL不会混淆数组元素的顺序?

这是问题的快速再现:

#!/bin/bash 
# : \ 
exec /home/binops/afse/eer/eer_SPI-7.3.1/tclsh "$0" "[email protected]" 

proc myProc { theArray } { 
    upvar $theArray theArrayInside 
    parray theArrayInside 
    puts "------" 
    foreach { key value } [array get theArrayInside] { 
    puts "$key => $value" 
    } 
} 

# MAIN 
set myArray(AQHI) AQHI 
set myArray(O3) 1 
set myArray(NO2) 2 
set myArray(PM2.5) 3 

parray myArray 
puts "------" 
myProc myArray 

输出是:

myArray(AQHI) = AQHI 
myArray(NO2) = 2 
myArray(O3) = 1 
myArray(PM2.5) = 3 
------ 
theArrayInside(AQHI) = AQHI 
theArrayInside(NO2) = 2 
theArrayInside(O3) = 1 
theArrayInside(PM2.5) = 3 
------ 
PM2.5 => 3 
O3 => 1 
NO2 => 2 
AQHI => AQHI 

通知我没有使用通用的键,如A,B,C和通用值样1, 2,3,你可能已经预料到了。这是因为订单不会与这些通用键/值混淆。也许这可以帮助识别问题。

请注意,即使在第一次拨打parray(订单现在是AQHI,NO2,O3,PM2.5;按字母顺序排列?),初始订单(AQHI,O3,NO2,PM2.5)也会丢失。然后再调用array get ...(反向?)

再次更改因此,无论如何,问题是:我怎样才能确保最初的订单保存?

回答

0

Tcl非常灵活,可以设计出许多方案来处理你想要的东西。这里有一个想法,它将你的密钥的顺序存储在数组本身内,假设空字符串不是数据中的有效密钥:

+0

使用这种方法,你将如何去找到某个值的关键? – Shawn 2011-06-03 14:49:08

+0

@Shawn,这里有一个方法:'foreach {key val} [array get ary] {if {$ val == $ search} {puts $ key; break}}' – 2011-06-03 14:54:05

+0

明白了,我结束了使用'proc array_getKeyFromValue {array_name value} {upvar 1 $ array_name theArray;设置returnValue“”; array_foreach key theArray {if {$ theArray($ key)== $ value} {set returnValue $ key; }} return $ returnValue; }' – Shawn 2011-06-03 15:10:24

6

你犯的错误是将Tcl数组等同于C语言中的那些语言,它们是元素列表。相反,Tcl数组是像Java中的HashMap一样的映射(从一个键到一个值),并且不保留元素的顺序。

你可能会更好的使用一个列表(如果你只有一些需要存储的项目)。

如果您使用的是8.5或更高版本,则如果您实际上具有键到值的映射,则为dict,因为字典是保存顺序图的映射。在8.5之前有Tcl版本的dict backports,但我不确定它们是否保持顺序(而且速度较慢)。

如果您不能使用8.5类型的字典和需要的键/值对,一个选择是使用键值对的列表,然后使用lsearch拔出你需要

> set mylist {{key1 value1} {key2 value2} {key3 value3}} 
> lsearch -index 0 $mylist key2 
0 
> lindex $mylist [list [lsearch -index 0 $mylist key2] 1] 
> value2 
> proc kv_lookup {dictList key} { 
     set index [lsearch -index 0 $dictList $key] 
     if {$index < 0} { 
      error "Key '$key' not found in list $dictList" 
     } 
     return [lindex $dictList [list $index 1]] 
    } 
> kv_lookup $mylist key2 
value2 

手册页值对于8.4是here

您可能还想看看关于Tcl的keyed lists的页面。它实现了我上面提到的,以及一些其他有用的命令。

有关“有序”映射和无序映射之间不同之处的示例,您可以看看两个java类HashMap(无序)和LinkedHashMap(有序)。

+0

@RHSeeger:我坚持使用8.4。我使用一个数组是因为我真正想要的是一张地图!当然,没有办法做到这一点?另外,我是否正确地假设'parray'按键按字母顺序打印数组?我无法在文档中找到它,但我的测试似乎表明这种情况... – Shawn 2011-06-01 23:15:20

+0

如何使用列表来存储地图内容,如下所示:{AQHI => AQHI,O3 => 1 ,NO2 => 2,PM2.5 => 3}在我看来,列表不起作用。还是应该使用两个列表(一个用于键,一个用于值),并使用indeces使关键字=>值关联? – Shawn 2011-06-01 23:25:52

+0

@Shawn:实际上,当我评论时,我正在添加关于如何处理有序键/值对的说明。我还为您添加了8.4手册页的链接。 – RHSeeger 2011-06-01 23:26:14