Stumped on complex sort

Inspired by this thread (with variable-responsive html tables), I wanted to mock up a shiraz-style dynamic table that does the same things.

But I realized (in mocking up my suggestion) that I was stumped by the sorting needs of @mswho42 — which seem to combine :sortsub-style need (retrieve the value in the stack field, since that value is the basis of sort order) with sortby-style recourse to a separate tiddler (that contains the custom sort order for those values).


For a simpler example, documentation shows how to do
{{{ Friday Monday +[sortby{Days of the Week!!list}] }}}

… But if I have a list of tiddlers each with a day field, how do I get that list to sort based on their day field, but in the custom order? Seems to need a sortsub move, but I’m having trouble getting that play nice with sortby…?

<$vars compare-by-day="[get[day]sortby{Days of the Week!!list}]">

<$list filter="[[Amanda]] [[Jane]] +[sortsub<compare-by-day>]">

{{!!title}} — {{!!day}}

</$list>

The result is

Amanda — Friday
Jane — Monday

but of course I’m hoping to get it the other way `round … (which then should map onto the more complex problem in the other post)

???

Sorry, keyboard mishit posted before I finished.

1 Like

I don’t have time now to consider how we might get this right, but I can explain why it’s not meeting your expectations.

sortby<whatever> takes a list, and sorts that entire list based on their positions in whatever.

sortsub<converter> takes a list, uses the runnable converter (function, procedure, macro) to create an index for each element, then sorts the originals by that index.

The latter is more general, as we could derive sortby from sortsub in a fairly straightforward manner, but not vice versa.

Think of sortsub like this:

Amanda Jane  +[sortsub:number<letter-count>]
(calculate `Amanda -> 6` and `Jane -> 4`)
sort the pairs (Amanda, 6), (Jane, 4) numerically by their second element to get:
(Jane, 4), (Amanda, 6)
then extract the first components, to get:
Jane Amanda

I doubt this is the exact mechanism, but it should show the idea.

I will often use sortsub:string<by-last> with something like

\procedure by-last(tid) [<tid>get[last-name]] [<tid>get[first-name]] +join[~]]

Aside: TW seems to be missing the most powerful of JS’s sorting tools: supplying a comparator, which for any pair A and B returns a number which is negative if A should come before B, zero if it doesn’t matter, and positive if B should come before A. That’s harder to use, but quite powerful.

I mostly solved my own problem… Unsurprisingly, it’s actually easy to get the sort needed here — just so long as we go at it from the other end (which is pretty much the logic @mswho42 used in that other thread, though that approach employed nested list widgets):

\function sortby.StackOrder()
[{StackingOrder}enlist-input[]listed[stack]is[tiddler]]
\end

{{{ [sortby.StackOrder[]] +[format:titlelist[]] }}}

(And further conditions can be integrated into that same filter run.)

Or in the simplified example I started with, it might look like:

\function sortby.weekday()
[{Days of the Week!!list}enlist-input[]listed[day]is[tiddler]]
\end

<$list filter="[sortby.weekday[]]">
{{!!title}} — {{!!day}}<br>
</$list>

This does get the required order.

Alas, there’s still no “hook” that is easily harnessed by shiraz dynamic tables… which was the impetus — hoping I could get it set up so that the table could sort tiddlers according to a column/field with a proprietary (indirectly-established) order.