Reputation: 1
Though I read many options in lsort to do this, but in my case it is not working. I have a list of floating numbers like below
{898.465 348.700} {898.465 1511.400} {477.130 348.700} {898.465 730.200} {477.130 1511.400} {898.465 1121.400} {477.130 730.200} {477.130 1121.400}
I want to sort it by second index, so that I can get min and max value of 2nd index. I tried below things and got few outputs but nothing is of any help.
lsort -index end-1 -decreasing `$bbox_upper`
{477.130 348.700} {477.130 1511.400} {477.130 730.200} {477.130 1121.400} {898.465 348.700} {898.465 1511.400} {898.465 730.200} {898.465 1121.400}
lsort -index 1 -real $bbox_upper
{898.465 1121.400} {477.130 1121.400} {898.465 1511.400} {477.130 1511.400} {898.465 348.700} {477.130 348.700} {898.465 730.200} {477.130 730.200}
If you see in above outputs, the 2nd index 1511.400 is the biggest one, so it should come in the first sublist, but it is not coming
Can you please help.
Upvotes: 0
Views: 2850
Reputation: 137587
What exact version of Tcl are you using (using info patchlevel
to find out)? When I try it with 8.6.1, it works fine as long as I use all the options I need (and I'd also expect it to be fine with any 8.5-based or 8.4-based Tcl):
% info patchlevel
8.6.1
% lsort -index 1 -decreasing -real $bbox_upper
{898.465 1511.400} {477.130 1511.400} {898.465 1121.400} {477.130 1121.400} {898.465 730.200} {477.130 730.200} {898.465 348.700} {477.130 348.700}
I wouldn't use the index end-1
unless you mean “last but one”. For numeric sorting, the -real
option is right; -dictionary
might also work, but it's using a very different string-based algorithm (that has good results with values shown to users in things like lists of filenames in file chooser dialogs) and wouldn't be efficient for true floating point data.
If you need a more complex sort, such as using the first value of each pair as a tiebreak when the second value is the same, you've got a few options.
Secondary keys are usually best handled via sorting the data twice. It's not the most efficient technique, but it's easy to get right and Tcl's lsort
uses a stable sorting algorithm.
lsort -index 1 -decreasing -real [lsort -index 0 -decreasing -real $bbox_upper]
Alternatively, you can use the -command
option to delegate the ordering decision to some code you provide:
proc sorter {aValue bValue} {
foreach {ax ay} $aValue break
foreach {bx by} $bValue break
set diff [expr {$ay - $by}]
if {$diff == 0} {
set diff [expr {$ax - $bx}]
}
return [expr {$diff < 0 ? 1 : $diff > 0 ? -1 : 0}]
}
lsort -command sorter $bbox_upper
From 8.5 onwards, you can do this without introducing a helper procedure:
lsort -command {apply {{aValue bValue} {
lassign $aValue ax ay
lassign $bValue bx by
set diff [expr {$ay - $by}]
if {$diff == 0} {
set diff [expr {$ax - $bx}]
}
return [expr {$diff < 0 ? 1 : $diff > 0 ? -1 : 0}]
}}} $bbox_upper
You're advised that it is faster to use a procedure, and even faster still (at least in this case) a double sort.
Upvotes: 4