按其值对对dict排序

时间:2014-02-10 11:53:16

标签: sorting dictionary tcl

我有一个看起来像这样的字典:

未排序:

12 {12 489} 29 {89 12} 27 {301 302} 26 {489 329} 8  {89 302} 55 {44 301}

我想这样排序:

55 {44 301} 27 {301 302} 8  {89 302} 29 {89 12} 12 {12 489} 26 {489 329}

如您所见,大多数情况下,前一个条目的第二个键值与下一个条目的第一个键条目相同。 (最后两个条目中的12489

这虽然没有要求。第二个和第三个条目的302也满足第二个和第三个条目中存在的“链”的要求。

我唯一要做的就是以这种方式对这些条目进行排序,使大括号中的值形成一个不间断的链。

如果结果在示例中显示或者是否镜像,则无关紧要。

从TCL 8.6开始,我可以使用步幅做类似于Sort Tcl dict by value的操作。但我坚持这个(Tcl8.5.9)版本。最简单的方法是什么?

1 个答案:

答案 0 :(得分:1)

我不知道这是否是最简单的方法:

set x [dict create 12 {12 489} 29 {89 12} 27 {301 302} 26 {489 329} 8 {89 302} 55 {44 301}]

# transform the dict into a list of lists
dict for {k v} $x {lappend unsorted [list $k $v]}
lappend sorted [lindex $unsorted 0]
set unsorted [lrange $unsorted 1 end]

# keep going until there's nothing more to add to the sorted list
while {[llength $unsorted] != 0} {
    set changed false

    for {set idx 0} {$idx < [llength $unsorted]} {incr idx} {
        set elem [lindex $unsorted $idx]
        lassign [lindex $elem end] a b

        set head [lindex $sorted 0 end]
        set tail [lindex $sorted end end]

        if {$a in $head || $b in $head} {
            set sorted [linsert $sorted 0 $elem]
            set changed true
        } elseif {$a in $tail || $b in $tail} {
            lappend sorted $elem
            set changed true
        }

        if {$changed} {
            set unsorted [lreplace $unsorted $idx $idx]
            break
        }
    }

    # avoid infinite loop if the unsorted list is not empty, but
    # contains nothing to add to the sorted list
    if {! $changed} break
}

foreach elem $sorted {dict set y {*}$elem}

puts "Unsorted: $x"
puts "Sorted:   $y"
Unsorted: 12 {12 489} 29 {89 12} 27 {301 302} 26 {489 329} 8 {89 302} 55 {44 301}
Sorted:   55 {44 301} 27 {301 302} 8 {89 302} 29 {89 12} 12 {12 489} 26 {489 329}