Arrays 我如何确保TCL不会';t打乱数组元素的顺序?

Arrays 我如何确保TCL不会';t打乱数组元素的顺序?,arrays,tcl,Arrays,Tcl,问题在于,我在数组中“插入”元素的顺序在整个脚本执行过程中都会发生变化 下面是问题的快速重现: #!/bin/bash # : \ exec /home/binops/afse/eer/eer_SPI-7.3.1/tclsh "$0" "$@" proc myProc { theArray } { upvar $theArray theArrayInside parray theArrayInside puts "------" foreach { key value } [a

问题在于,我在数组中“插入”元素的顺序在整个脚本执行过程中都会发生变化

下面是问题的快速重现:

#!/bin/bash
# : \
exec /home/binops/afse/eer/eer_SPI-7.3.1/tclsh "$0" "$@"

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,PM2.5)也会丢失。然后在调用
数组get…
(反转?)时再次更改它


所以不管怎么说,问题是:我如何确保初始顺序保持不变?

将Tcl数组等同于像C这样的语言中的数组是一个错误,因为C是元素列表。相反,Tcl数组是映射(从一个键到一个值),就像Java中的HashMap一样,元素的顺序不保留

您最好使用列表(如果您只需要按顺序存储一些项目)

如果您使用的是8.5或更高版本,那么如果您实际上有一个键到值的映射,因为字典是保序映射。8.5之前的Tcl版本有dict后端口,但我不确定它们是否保持了顺序(而且速度较慢)

如果您不能使用8.5 dict并且需要键/值对,一个选项是使用键-值对列表,然后使用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
>设置mylist{{key1 value1}{key2 value2}{key3 value3}
>L搜索-索引0$mylist键2
0
>lindex$mylist[列表[L搜索-索引0$mylist键2]1]
>价值2
>proc kv_查找{dictList key}{
设置索引[L搜索-索引0$dictList$key]
如果{$index<0}{
错误“在列表$dictList中找不到键“$Key”
}
return[lindex$dictList[list$index 1]]
}
>kv_查找$mylist键2
价值2
8.4的手册页如下:

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


对于有序“映射”和无序“映射”之间的差异示例,您可以查看两个java类(无序)和(有序)

Tcl非常灵活,可以设计许多方案来处理您想要的内容。假设空字符串不是数据中的有效键,则可以将键的顺序存储在数组本身中:

proc array_add {ary_name key value} {
    upvar 1 $ary_name ary
    set ary($key) $value
    lappend ary() $key
}

proc array_foreach {var_name ary_name script} {
    upvar 1 $var_name var
    upvar 1 $ary_name ary
    foreach var $ary() {
        uplevel 1 $script
    }
}

array_add a foo bar
array_add a baz qux
array_add a abc def
array_add a ghi jkl

array_foreach key a {puts "$key -> $a($key)"}
# foo -> bar
# baz -> qux
# abc -> def
# ghi -> jkl

array names a
# ghi {} foo baz abc

array get a
# ghi jkl {} {foo baz abc ghi} foo bar baz qux abc def

parray a
# a()    = foo baz abc ghi
# a(abc) = def
# a(baz) = qux
# a(foo) = bar
# a(ghi) = jkl

@我被8.4卡住了。我使用数组,因为我真正想要的是一张地图!真的没有办法吗?另外,我假设
parray
打印出按键字母顺序排序的数组,对吗?我在文档中找不到它,但我的测试似乎表明了这一点……我如何使用列表来存储这样一个映射的内容:{aqi=>aqi,O3=>1,NO2=>2,PM2.5=>3}在我看来,列表不起作用。或者我应该使用两个列表(一个用于键,一个用于值)并使用索引进行键=>值关联吗?@Shawn:实际上,当你发表评论时,我正在添加如何处理有序键/值对的描述。我还为您添加了一个指向8.4手册页的链接。@Shawn:
parray
以简单的排序顺序打印带有键的元素(它在引擎盖下使用
lsort[array names]
),尽管这确实没有文档记录;它不会产生其他Tcl命令(简单地)可以使用的输出,因为它是用于调试的。这也是一个简单的过程
info body parray
将确切地告诉您它是如何发挥其魔力的。当我使用键控列表为这个问题制定答案时,我遇到了一个错误:使用此方法,您将如何查找某个值的键?@Shawn,这里有一种方法:
foreach{key val}[array get ary]{if{$val=$search}{puts$key;break}
明白了,我最终使用了
proc array\u getKeyFromValue{array\u name value}{upvar 1$array\u name theArray;set returnValue”“;array\u foreach key theArray{if{$theArray($key)==$value}{set returnValue$key;}return returnValue$returnValue;