2

我是 tcl 的新手。我需要对值列表进行排序并保存索引。我有 2 个列表,我想对 listA 进行排序,但是我想对 listB 进行排序,并保留 listA 的索引。

例如:

set listA {5 6 7 3 4 7 8 9}
set listB {0 1 2 3 4 5 6 7}

set sort_listA [lsort $listA]

现在sort_listA3 4 5 6 7 7 8 9

我想对listB保持相同索引的列表进行排序sort_listA

3 4 0 1 2 5 6 7

换句话说,我需要对两个列表进行排序listA。谁能帮我?

4

1 回答 1

3

这正是可以选择的任务类型lsort-indices需要 8.5 或更高版本)。它不是排序值列表,而是将索引列表返回到原始列表中,按照您检索它们以获得排序列表的顺序,这非常适合您的任务。这个交互式会话(在 Tcl 8.6 中,所以我有lmap)是指示性的:

% set listA {5 6 7 3 4 7 8 9}
5 6 7 3 4 7 8 9
% set listB {0 1 2 3 4 5 6 7}
0 1 2 3 4 5 6 7
% set idxs [lsort -indices $listA]
3 4 0 1 2 5 6 7
% lmap i $idxs {lindex $listA $i}
3 4 5 6 7 7 8 9
% lmap i $idxs {lindex $listB $i}
3 4 0 1 2 5 6 7

如果您仍在使用 8.5,则可以使用foreach重新映射;使用过程更容易:

proc mapindices {indexlist valuelist} {
    set result {}
    foreach i $indexlist {
        lappend result [lindex $valuelist $i]
    }
    return $result
}
set listA {5 6 7 3 4 7 8 9}
set listB {0 1 2 3 4 5 6 7}
puts [mapindices [lsort -indices $listA] $listB]

现在,在 8.4(不再支持!)中没有索引选项,因此您需要做更多的工作。

proc lsortIndices {list} {
    # Pair each value up with its index
    set zipped {}
    set idx -1
    foreach val $list {
        lappend zipped [list [incr idx] $val]
    }

    # Do the sorting by the value of the pair
    set sorted [lsort -index 1 $zipped]

    # Unpack the indices from the pairs to get the result
    set result {}
    foreach pair $sorted {
        lappend result [lindex $pair 0]
    }
    return $result
}

但是,那时您可能只是将两个列表压缩在一起并更直接地工作:

set zipped {}
foreach valA $listA valB $listB {
    lappend zipped [list $valA $valB]
}

set sorted [lsort -index 0 $zipped]

set listAsorted {}
set listBsorted {}
foreach pair $sorted {
    lappend listAsorted [lindex $pair 0]
    lappend listBsorted [lindex $pair 1]
}

使用比 8.4 更旧的 Tcl 版本需要您使用该-command选项,这真的很慢。

于 2018-10-26T16:52:56.000 回答