如何按值对 Tcl 数组进行排序?

How do I sort a Tcl array by values?

例如如何对数组输出进行排序 来自
的样本输入 放“$word $count($word)”}

示例输入

Roger 15
Martin 18
Jemmy 16
Jon 12
Sara 12

预期输出

Martin 18
Jemmy 16
Roger 15
Jon 12
Sara 12

你可能有这样的事情

array set count { Roger 15 Martin 18 Jemmy 16 Jon 12 Sara 12 }
foreach word [array names count] {puts "$word $count($word)"}
Jemmy 16
Sara 12
Jon 12
Martin 18
Roger 15

你想要做的是将数组转换为列表,成对地跨过它并根据数量对对进行排序:

foreach {name num} \
        [lsort -integer -decreasing -stride 2 -index 1 [array get count]] \
        {puts "$name $num"}
Martin 18
Jemmy 16
Roger 15
Sara 12
Jon 12

参考文献:
http://www.tcl.tk/man/tcl8.6/TclCmd/lsort.htm
http://www.tcl.tk/man/tcl8.6/TclCmd/foreach.htm

Tcl 的数组总是 未排序的 ,事实上,当您在其中添加元素时,元素的顺序会不时发生变化(当底层哈希 table 是重建)。要获得所需的输出,最好获取数组的内容并使用 lsort-stride 2 选项:

# Convert the array to a Tcl list
set contents [array get count]

# First sort by name, as a secondary key
set contents [lsort -stride 2 -index 0 $contents]
# Then sort by count, descending, as a primary key
set contents [lsort -stride 2 -index 1 -integer -decreasing $contents]

# Print the values
foreach {name score} $contents {
    puts "$name $score"
}

-stride选项需要 Tcl 8.6。


在旧版本的 Tcl 中,您必须将内容打包成 list 个元组:

# Convert the array to a list of pairs
set contents {}
foreach {name score} [array get count] {
    lappend contents [list $name $score]
}

# Do the sorting
set contents [lsort -index 0 $contents]
set contents [lsort -index 1 -integer -decreasing $contents]

# Print the values
foreach pair $contents {
    # Unpack; *not* needed here, but useful for anything more complicated
    foreach {name score} $pair break
    # You could use “lassign $pair name score” but you're on 8.4
    puts "$name $score"
}

请注意,Tcl 8.4 是不受支持的软件,即使出于安全问题也是如此,并且 8.5 只剩下一两年的延长支持寿命。我们握住人们的手的时间是有限度的……

Tcl < 8.6 的解决方案:

给定

array set count {Roger 15 Martin 18 Jemmy 16 Jon 12 Sara 12}

排序输出的方法是

set L [list]
foreach {k v} [array get count] {
    lappend L [list $k $v]
}
foreach e [lsort -index 1 -decreasing -integer $L] {
    lassign $e k v
    puts "$k $v"
}

解释:

  1. 使用 array get.
  2. 获取交错键和值的平面列表
  3. 从中生成一个 key/value 的列表——列表的列表。
  4. 给定该列表,使用传递给它的 lsort 命令对其进行排序 -index 1 选项使 lsort 解释 list 它按列表排序,并在索引 1 处使用它们的元素 (第 2 个位置)用于排序。
  5. 要打印出排序列表的元素,您需要提取 键和每个返回的值。最简单的方法是使用 lassign 但如果您的 Tcl < 8.5,您可以使用 foreach {k v} $e break 欺骗或直接访问元素使用 lindex $e 0lindex $e 1 分别获取键和值。