Это именно та задача, для которой 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]
}
Работа с более старыми версиями Tcl, чем 8.4, потребует от вас использования опции -command
, и это очень медленно.