基于值的 Tcl 数组排序

Tcl array sorting based on values

我有一个数组,其中包含动态 'keys' 和与之关联的值。 我想根据值对数组进行排序,并希望能够从排序后的数组中检索 'keys'。 例如,假设我有,

for {set i 0} {$i < [db_get_nrows $rs]} {incr i} {
    set x [db_get_col $rs $i abc]
    set ARRAY_A($x) [db_get_col $rs $i def]
}

所以,我的数组看起来像,

ARRAY_A(111) 10
ARRAY_A(222) 50
ARRAY_A(333) 20

现在,我想根据它的值对这个数组进行排序(首先是 50,然后是 20,然后是 10)。然后我对它的键(222、333 和 111)感兴趣,以便进一步处理。

我在 Internet 上找不到太多关于此类具有动态生成键的数组的信息。 非常感谢任何帮助。

谢谢。

好吧,我只想首先提一下,您不能对数组进行排序,因为它们实际上并没有固定的顺序,但是它们的保存方式使得 easier/faster 解释器可以检索值。

如果你想按照值的顺序获取数组的键,你可以使用类似的东西:

set key_value [lmap {key val} [array get ARRAY_A] {list $key $val}]
set key_value [lsort -index 1 -integer -decreasing $key_value]

列表 key_value 现在包含按值降序排列的 key/value 对数组。 -index 1 表示排序是按子列表的第二个元素排序(Tcl 有从 0 开始的列表)。 -integer 只是指示我们正在对整数进行排序(而不是使用字典排序)。您只需要从列表中获取密钥:

foreach n $key_value {
    puts [lindex $n 0]
}

如果你愿意,你可以将上面的内容组合在一个循环中(我将循环和第二行组合在一起,添加第一行会使它看起来有点太多):

foreach n [lsort -index 1 -integer -decreasing $key_value] {
    puts [lindex $n 0]
}
% set tcl_version
8.6
% array set n {111 10 222 50 333 20}
% parray n
n(111) = 10
n(222) = 50
n(333) = 20
% set l [array get n]
333 20 222 50 111 10
% lsort -stride 2 -integer -index 1 $l
111 10 333 20 222 50
% lsort -stride 2 -integer -decreasing -index 1 $l
222 50 333 20 111 10
% 

您可以将它们作为具有预期顺序的列表获取,然后尝试进一步应用您的逻辑。

这部分答案主要是 Dinesh 答案的补充,本身并不完整。

创建包含按值排序的数组元素的列表后,可以将其放入字典(这是另一种关联列表结构):

set d [lsort -stride 2 -integer -decreasing -index 1 $l]

字典将保留插入顺序并允许轻松访问,例如钥匙:

dict keys $d
# -> 222 333 111

eta[​​=33=]

如果你不能使用lmap-stride,你仍然可以像这样生成一个字典:

set pairs {}
foreach {a b} [array get ARRAY_A] {
    lappend pairs [list $a $b]
}
set DICT_A [concat {*}[lsort -index 1 -integer -decreasing $pairs]]

此方法将元素打包到 "pairs" 中,对打包列表进行排序,然后将其解包到一个平面列表中,以用作上面的字典。

文档:array, concat, dict, foreach, lappend, list, lsort, set