Multiple sort order in Tiddlywiki

311 views
Skip to first unread message

Mohammad

unread,
Dec 6, 2019, 10:53:03 PM12/6/19
to TiddlyWiki
Assume you have a bunch of tiddlers 
  • all tagged with data
  • all have three fields fa, fb, fc

How one can produce a list of tiddlers where they are
  • sorted first by fa
  • then by field fb
  • then by field fc

This means to keep the multiple sort order!

--Mohammad

Mark S.

unread,
Dec 6, 2019, 11:47:14 PM12/6/19
to TiddlyWiki

There are different approaches. The easiest would be to make a button that, when pressed, populates a fourth field that can then be sorted.

Here's an approach that doesn't require two steps, but it does assume that "@@" is reserved:

\define sortus()
<$vars lb="[[" rb="]]">
<$list filter="[has[fa]]">
<$list filter="[<currentTiddler>addprefix[@@]addprefix{!!fc}addprefix{!!fb}addprefix{!!fa}addprefix<lb>addsuffix<rb>]"/>
</$list>
</$vars>
\end

<$wikify text=<<sortus>> name="ready2sort">
<$list filter="[enlist<ready2sort>sort[]]" variable="sorted">
<$list filter="[<sorted>split[@@]rest[]]"/>
</$list>
</$wikify>


TonyM

unread,
Dec 7, 2019, 12:12:44 AM12/7/19
to TiddlyWiki
I do not mean to sound competitive, but all you need is .nested lists

<$list fiter="[all[tiddlers]each[state]get[state]sort[]]" variable=state>
   <$list fiter="[all[tiddlers]state
<state>each[region]get[region]sort[]]" variable=region>
       <$list fiter="[all[tiddlers]state
<state>region<region>sort[]]">
           <
<currentTiddler>>
       </$list>
   </$list>
</$list>
gives a list sorted by state then region then tiddler title
not tested against data

note the groups state and region use "each" and the inner list only lists those with the same state<state> and region<region> at a time

to keep it tidy i use the same name as the field as the variable name generated by the each lists.

state<state> means list all tiddlers with the state field = the value in the `<<state>> variable.

you could wrap the whole thing or make it more levels deep however a new outer filter may need every filter to be updated. See how every list filter starts with all[tiddlers] a fresh, so if you want to operate on all tiddlers this is fine but only with tag[a] would need to read [all[tiddlers]tag[a] to each filter.
              
   
Regards
Tony

Jed Carty

unread,
Dec 7, 2019, 4:18:06 AM12/7/19
to TiddlyWiki
I have been thinking about making an explicitly stable sort operator for tiddlywiki so this is easier.

In general unstable sorts can be much faster than stable sorts so by default some (or most?) browsers use unstable sorting algorithms like quicksort.

A stable sort keeps elements that have the same ranking in the sorting in the order they were at the input.

A stable sorting operator would allow you to do this in one filter, the only problem is that it may be slower than the normal sort operator. Unless you are doing thousands of these operations in a row that shouldn't matter.

My biggest concern with making this is having multiple sort operators might be confusing without good detailed documentation about what stable vs unstable means.

TonyM

unread,
Dec 7, 2019, 6:25:12 AM12/7/19
to TiddlyWiki
Jed,

Good of you to think about this. Perhaps rather than take the path you are thinking what about looking at intermediate sorts or finding a way to do do nested filters.

I am thinking of my nested list algorithium above which needs only the input and state and region to be provided. Perhaps a widget or macro we provide input and one or more group folters, that builds the required nested lists.

Would that produce the type of sort you suggest.

Regards
Tony

Mark S.

unread,
Dec 7, 2019, 9:11:54 AM12/7/19
to TiddlyWiki
Yes. There are multiple ways of doing this. When I first started, I wanted to have only one filter. Unfortunately, that wasn't possible. I ended up with more list widgets than a simple nested list approach. BUT, you can now add more levels of sorting without adding any more lists. So if you had 6 or 7 levels of sorting, it might be a useful approach. You could also wrap with a macro with say 8 "level" markers to have a more universal solution.

Mark S.

unread,
Dec 7, 2019, 9:19:41 AM12/7/19
to TiddlyWiki
You'd have to implement the sorting algorithm by hand, right? You wouldn't be able to use the underlying JS engine.

I imagine that that would be a lot slower. Writing in interpreted script vs. executable code.

But, computers are getting faster these days. Not mine, mind you. But some peoples'.

If you gave it a name like "stable-sort" there would be no confusion, except for people who don't check the docs.

What's really needed is for JS to allow developers the ability to specify the kind of sort. I think Java may have that level of specificity.

Mohammad

unread,
Dec 7, 2019, 3:06:10 PM12/7/19
to TiddlyWiki
Thanks Mark!
It works but its tricky.

--Mohammad

Mohammad

unread,
Dec 8, 2019, 11:26:42 AM12/8/19
to TiddlyWiki
Tony!
 Your solution seems smart one!
 I have corrected a bit the code and have attached a working example!
 I will add it to TW-Scripts.

To test the demo, open tiddlywiki.com and drop the attached bundle into it!

Cheers
Mohammad

multi-sort.json

Mohammad

unread,
Dec 8, 2019, 1:44:20 PM12/8/19
to TiddlyWiki


On Saturday, December 7, 2019 at 8:42:44 AM UTC+3:30, TonyM wrote:
I do not mean to sound competitive, but all you need is .nested lists

<$list fiter="[all[tiddlers]each[state]get[state]sort[]]" variable=state>
   <$list fiter="[all[tiddlers]state
<state>each[region]get[region]sort[]]" variable=region>
       <$list fiter="[all[tiddlers]state
<state>region<region>sort[]]">
           <
<currentTiddler>>
       </$list>
   </$list>
</$list>
gives a list sorted by state then region then tiddler title
not tested against data

note the groups state and region use "each" and the inner list only lists those with the same state<state> and region<region> at a time

to keep it tidy i use the same name as the field as the variable name generated by the each lists.

state<state> means list all tiddlers with the state field = the value in the `<<state>> variable.

you could wrap the whole thing or make it more levels deep however a new outer filter may need every filter to be updated. See how every list filter starts with all[tiddlers] a fresh, so if you want to operate on all tiddlers this is fine but only with tag[a] would need to read [all[tiddlers]tag[a] to each filter.

What do you think if we omit the all[tiddlers]. I think the input of every filter is all[tiddlers] or all[tiddlers+shadows] so it should not affect the performance in this case! What do you think?

TonyM

unread,
Dec 11, 2019, 8:34:57 PM12/11/19
to TiddlyWiki
Mohammad,

Sorry for the delay in a response.

I used all tiddlers to include only the subset of what would be most likely in a query of state and region tiddlers. This acts to limit the default.

I have no objection to your suggestion, however since this part of the filter needs to be the same at all levels of the nested lists, perhaps abstracting this to a subfilter makes more sense since you need only edit in one place.

Perhaps a better approach would be a subfilter, (This code untested against data)
\define tiddlerset-filter() [all[]]
<$list fiter="[subfilter<tiddlerset-filter>each[state]get[state]sort[]]" variable=state>
   <$list fiter="[subfilter<tiddlerset-filter>state<state>each[region]get[region]sort[]]" variable=region>
       <$list fiter="
[subfilter<tiddlerset-filter>state<state>region<region>sort[]]">
           <
<currentTiddler>>
       </$list>
   </$list>
</$list>

Regards
Tony

Mohammad

unread,
Dec 12, 2019, 12:41:32 AM12/12/19
to TiddlyWiki
Good solution!

Thanks Tony!
Reply all
Reply to author
Forward
Message has been deleted
0 new messages