我怎样才能确保TCL不会搞乱数组元素的顺序?

时间:2011-06-01 23:04:13

标签: 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 } [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,O3,NO2,PM2.5)也会丢失(订单现在是AQHI,NO2,O3,PM2.5;按字母顺序排序? )。然后在调用array get ...(反转?)

后再次更改

所以无论如何,问题是:我如何确保保留初始订单?

2 个答案:

答案 0 :(得分:6)

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

您可能最好使用列表(如果您只需要按顺序存储多个项目)。

如果您使用的是8.5或更高版本,则dict如果您实际拥有键值到映射的映射,则字典是订单保留映射。在8.5之前有一些dcl向Tcl版本的移植,但我不确定它们是否保留顺序(并且它们更慢)。

如果你不能使用8.5 dicts并且需要键/值对,一个选项是使用键值对列表然后使用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

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

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

答案 1 :(得分:0)

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
相关问题