This is a tip for those who have trouble doing more complex sorts. I haven’t noticed this mentioned, although I haven’t looked thoroughly.
If you need a multipart sort, you can do it with separate steps.
[some[selection]of[tiddlers]sort[first-name]sort[last-name]]
\______________/\______________/
secondary sort / \ primary sort
Note that the more important feature you’re sorting for comes last.
This is probably not as efficient as what you might do with sortsub
, but it’s simpler to work with, and it’s more powerful. sortsub
will generate keys from your items and sort by those keys. That works great for some cases, but it doesn’t work well, for instance, with mixed number and string types as you would have with street addresses. This technique covers those as well.
Note that you can of course extend this to three sort criteria or more. Just put them in reverse order, so that the most significant criterion comes last, and the least significant one comes first, etc.
If there are other simple ways to do this built into TW, I’d love to hear more!
Technical Explanation
This runs two separate sort operations. First we sort the inputs by first-name
. Now, on that new sorted list, we run a second sort operation on last-name
. But in all modern JavaScript implementations, sorts are stable, that is, values that the comparator says are equal (say, having the same last name) are returned in the same order they were in the original list.
So after sorting by first name, we might get:
Jane Roe
Jane Doe
John Q. Public
John Doe
John Roe
then when we sort by last name, we never alter the relative order of the two Roe’s we’ve already done, so Jane Roe will end up before John Roe, so we will get
Jane Doe
John Doe
John Q. Public
Jane Roe
Jane Doe
There are other good sorting algorithms that are not stable. But being stable, which is now specified
for JS engines, gives us the ability to do this consistently.
Example
The Address issue was my use-case. I have some Address
objects that I want to appear in custom search results. They have a number of fields, including ones like these:
address:142 Bunker Hill Rd - Apt B
apt: B
street: Bunker Hill Rd
street-number: 142
as well as city, state, postal code fields, and latitude, longitude, altitude ones. If I sort my search results by the address
field above, I get an ordering like this:
10 Hickory Hill Dr
104 Bunker Hill Rd
105 Boston Hill Rd
109 Bunker Hill Rd
109 Long Hill Rd
11 Hickory Hill Dr
112 Bunker Hill Rd
…
84 Long Hill Rd
85 Long Hill Rd
93 Boston Hill Rd
95 Bunker Hill Rd
97 Long Hill Rd
(This was a search for “hill”, which in my case also lists the people with the last names “Hill”, “Hills”, “Phillips”, and “Schilling”.)
That is definitely not the order I want. I would much rather get
93 Boston Hill Rd
105 Boston Hill Rd
95 Bunker Hill Rd
104 Bunker Hill Rd
109 Bunker Hill Rd
112 Bunker Hill Rd
10 Hickory Hill Dr
11 Hickory Hill Dr
…
84 Long Hill Rd
85 Long Hill Rd
97 Long Hill Rd
109 Long Hill Rd
In other words, I want to sort by street name first, and then ,if the streets match, by street number. I want numeric sorting on the street number, so that 23
comes before 100
, which is different from the JS standard lexicographic sorting, which sorts character-by-character.
Using the technique above, I wrote:
[search[for]matching[addresses]nsort[street-number]sort[street]
\__________________/\__________/
secondary sort / \ primary sort
And it sorts them the way I choose.