lsort index vector

if 0 {Richard Suchenwirth 2004-08-27 - In the Tcl chatroom, JPS discussed an extension to lsort which returns a list of indices in sorted order (TIP#217) but for now, here's a pure-Tcl implementation: }

 proc lsort-indices list {
    if [llength $list] {
       set i -1
       foreach e $list {lappend tmp [list [incr i] $e]}
       foreach e [lsort -index 1 $tmp] {lappend res [lindex $e 0]}
       set res
    }
 }

if 0 {Testing:

 % lsort-indices {c b a}
 2 1 0
 % lsort-indices {}

 % lsort-indices {a a a}
 0 1 2

RS removed the initialisations of tmp and res, but then had to guard the body with a one-armed if - it implies "else {}", which is the correct return value for an empty list.


Lars H had this solution, which is said to be up to a third faster:

 proc lsort-indices itemL {
    set pairL [list]
    foreach item $itemL {
       lappend pairL [list $item [llength $pairL]]
    }
    set indexL [list]
    foreach pair [lsort -index 0 $pairL] {
       lappend indexL [lindex $pair 1]
    }
    return $indexL
 }

wdb This version allows all switches except -index (but I did not care of speed):

 proc lsort-indices args {
    set unsortedList [lindex $args end]
    set switches [lrange $args 0 end-1]
    set pairs {}
    set i -1
    foreach el $unsortedList {
        lappend pairs [list [incr i] $el]
    }
    set result {}
    foreach el [eval lsort $switches [list -index 1 $pairs]] {
        lappend result [lindex $el 0]
    }
    set result
 }

Now test it:

 % lsort-indices {9 10 11}
 1 2 0
 % lsort-indices -integer {9 10 11}
 0 1 2
 %

Additional list functions | Arts and crafts of Tcl-Tk programming }