TIP 326: Add -stride Option to lsort

Login
Author:		Kieran Elby <[email protected]>
State:		Final
Type:		Project
Tcl-Version:	8.6
Vote:		Done
Created:	01-Sep-2008
Keywords:	Tcl, lsort, sorting
Post-History:
Tcl-Ticket:	2082681

Abstract

This TIP adds a new option, -stride, to lsort to request that a list be treated as consisting of repeated groups of elements (as opposed to sublists), and that the the groups be sorted according to a chosen element within each group.

Rationale

Flat name-value pair lists are common in Tcl - consider the output of array get and dict create or the input to foreach.

It is surprising then that there is no command to directly sort such a list by either the name or the value elements, while preserving the name-value mapping.

Doing so currently requires turning a name-value pair list into a list of sublists, using the lsort -index option to sort them, then flattening the list again, which is rather fiddly and inefficient.

While sorting name-value pair lists is no doubt the most common use case, lists containing groups of more than two elements are also reasonably common, and so providing support for groups of any size seems useful and no harder to implement.

The option format follows the Feature Request here: https://sourceforge.net/support/tracker.php?aid=747083

Proposed Change

A new option, -stride, taking one parameter, grpSize will be added to the lsort command.

If -stride is supplied, the list will be treated as consisting of groups of grpSize elements, and the groups will be sorted by either their first element or, if the -index option is used, by the element within each group given by the first index passed to -index (which is then ignored by -index).

Elements always remain in the same position within their group.

The list length must be a multiple of grpSize, which in turn must be at least 2.

Examples

 lsort -stride 2 {carrot 10 apple 50 banana 25}

returns "apple 50 banana 25 carrot 10"

 lsort -stride 2 -index 1 -integer {carrot 10 apple 50 banana 25}

returns "carrot 10 banana 25 apple 50"

 lsort -stride 3 -index {0 1} {{Bob Smith} 25 Audi {Jane Doe} 40 Ford}

returns "{Jane Doe} 40 Ford {Bob Smith} 25 Audi" (since Smith, which is at index 1 of element 0 of the first group comes after Doe, which is at the same position in the next group of 3.)

Reference Implementation

Available online at https://sourceforge.net/support/tracker.php?aid=2082681

Compatibility

Since this is a new and unambiguous option, and since the distinction between the options and the list to sort is clear, no compatibility problems are expected.

Limitations

Only one element in each group can be used for comparison; it's not possible to compare groups element-by-element.

Further Thoughts

There may be some merit in adding a similar option to lsearch.

The name-value pair case is common enough that an argument could be made for adding -pairname and -pairvalue options as synonyms for -stride 2 -index 0 and -stride 2 -index 1 respectively.

Copyright

This document has been placed in the public domain.