2011-06-01 75 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