How can I sort a Names to make Name.Surname_(SAK3) before Name.Surname_(SAK5) before Name.Surname_(SBK5) …
You can use the :sort[...] filter run prefix to sort a list of input items using a “subfilter” to compute the value to sort by for each input item. The computed value is only used to perform the sort, and :sort[...] returns the original list of input items in the new sorted order.
Something like this:
{{{ [some filter to get names] :sort:string[{!!title}split[_]nth[2]] }}}
-e
Thank you but is it Sorten by the last char and then by the secondlast….
ok… try this:
{{{ [some filter to get names] :sort:string[{!!title}split[_]nth[2]split[]reverse[]join[]] }}}
The :sort subfilter:
-
{!!title}split[_]nth[2]gets the “(…)” suffix -
split[]reverse[]join[]then breaks the suffix into single characters, reverses the order of the characters, and then rejoins them to sort by the reversed text, e.g.,(SAK3)becomes)3KAS(
-e
Thank you again…it is even trickier: I have to split the content of a field to get the titles.
<$list filter="[{$:/temp/Kursliste}splitregexp[\n]]…???.. :sort:string[{!!title}split[_]nth[2]split[]reverse[]join[]]" variable=each-line>
Could you give us a list of 5 - 10 names and the desired resulting sort order?
Hi @Scott_Sauyet voilà
Name.Surname_(SAK3)
Different.Surnamee_(SAK5)
autre.Nom_(SBK5)
Sorted by the stuff in the brackets in reverse…
As said above devided by \n and pasted into an edit-field
I’m assuming that group is already sorted as you like, correct?
It’s still not clear to me. If we added these, where would they go in the list?
autre Nom_(ABC4)autre Nom_(ABC6)Name Surname_(SAK15)Alfred Surname_(SAK3)Alfred Syname_(SAK3)
Alfred Surname_(SAK3)
Alfred Syname_(SAK3)
autre Nom_(ABC4)
autre Nom_(ABD4)
autre Nom_(ABC6)
Name Surname_(SAK15) I guess doublenumbers wont appear.
\define setto()
<$action-setfield $tiddler="$:/temp/Kursliste" list=<<fillo>>/>
\end
<$button class="tc-btn-invisible">Generate
<$set name="fillo" filter="[{$:/temp/Kursliste}splitregexp[\n]]">
<<setto>>
</$set>
</$button>
<$list filter="[list[$:/temp/Kursliste]] :sort:string[{!!title}split[_]nth[2]split[]reverse[]join[]]" >
{{!!title}}
</$list>
T
Well this is really tricky, I already came up with strage solutions which did not work 
Not entirely sure if I understood it fully, anyway I give this a try before I’m out of the door:
\function reorder.name( name )
[<name>split[_]nth[2]split[]reverse[]join[]] [<name>split[_]butlast[]] +[join[]]
\end
<$let list=
`
autre Nom_(ABD4)
Alfred Syname_(SAK3)
autre Nom_(ABC6)
autre Nom_(ABC4)
Alfred Surname_(SAK3)
`
>
Original: <br>
<$list filter="[<list>splitregexp[\n]]">
<<currentTiddler>> <br>
</$list>
Interim: <br>
<$list filter="[<list>splitregexp[\n]] :map[function[reorder.name],<currentTiddler>]" >
<<currentTiddler>> <br>
</$list>
Sorted: <br>
<$list filter="[<list>splitregexp[\n]] :sort:string[function[reorder.name],<currentTiddler>]" >
<<currentTiddler>> <br>
</$list>
Output is:
Original:
autre Nom_(ABD4)
Alfred Syname_(SAK3)
autre Nom_(ABC6)
autre Nom_(ABC4)
Alfred Surname_(SAK3)
Interim:
)4DBA(autre Nom
)3KAS(Alfred Syname
)6CBA(autre Nom
)4CBA(autre Nom
)3KAS(Alfred Surname
Sorted:
Alfred Surname_(SAK3)
Alfred Syname_(SAK3)
autre Nom_(ABC4)
autre Nom_(ABD4)
autre Nom_(ABC6)
This is very clever, and much simpler than anything I had considered.
But I have no idea if it meets the requirements, which are still fairly unclear to me. While I tried to tease them out with examples, I don’t think we ever got enough to demonstrate. But i think we can build a similar solution to more complex requirements just by writing a more sophisticated version of your reorder.name.
Your technique takes the “reverse” quite literally, and so would place Name Surname_(BMX5) before Name Surname_(AMZ5) (because the 5s are the same and XMB comes before ZMA.) I would guess that the opposite is what’s wanted (because the 5s are the same and AMB comes before BMX.) But it is only a guess.
I won’t try to implement the following unless I hear from the OP that it’s right, but this is my guess about what’s desired:
We split the name into four components,
A,B,C, andD, so that, for instance, inAutre Nom_(ABC5), we have{A: 'Autre', B: 'Nom', C: 'ABC', D: '5'}.We sort first on
D.Zebediah Zillow_(ZYX3)comes beforeAnnie Applegate_(ABC8)because3comes before8.Then we sort on
C.Zebediah Zillow_(ABC5)comes beforeAnnie Applegate_(XYZ5)becauseABCcomes beforeXYZ.Next is
B.Zebediah Applegate_(PDQ4)comes beforeAnnie Zillow_(PDQ4)becauseApplegatecomes beforeZillow.Finally is
A.Annie Applegate_(PDQ4 )comes beforeZebediah Applegate_(PDQ4)becauseAnniecomes beforeZebediah.
Does that capture it correctly, @JanJo?
Yes, it does seem unusual to “reverse” entirely. Let’s hear from @JanJo.
But i think we can build a similar solution to more complex requirements just by writing a more sophisticated version of your
reorder.name.
Yes. That solution is not mine though, I learnt it from this forum. It’s handy in a filter expression processing a stream of titles. You call a function with one title, construct various parts concurrently using the same title, then join the parts together and return it to the filter stream. Useful for processing URLs, but also names in this case. It should have a name so the technique could be more commonly known.
Ok, I lied. I had a boring meeting, and played with this. I came up with this variant on @jacng’s post. It works as expected, but would be fragile, breaking down in the face of more complex names, such as “Jo van der Linde”. It also only works if the number at the end is a single digit, which the OP seemed to indicate is fine. We could write a more sophisticated version to overcome the second problem, but I don’t know how to deal with the first one at all, not unless our names have separate first and last name fields.
It looks like this:
\function get.first(name) [<name>split[ ]first[]]
\function get.last(name) [<name>split[ ]last[]split[_]first[]]
\function get.letters(name) [<name>split[(]last[]split[)]first[]split[]butlast[]join[]]
\function get.digit(name) [<name>split[(]last[]split[)]first[]split[]last[]]
\function reorder.name(name) [get.digit<name>] [get.letters<name>] [get.last<name>] [get.first<name>] +[join[~]]
<$let names=
`Zebediah Zillow_(ABC5)
Zebediah Zillow_(XYZ3)
Annie Applegate_(ABC8)
Fred Flinstone_(XYZ4)
Zebediah Applegate_(PDQ4)
Wilma Flintstone_(ABC4)
Annie Applegate_(XYZ5)
Zebediah Applegate_(PDQ5)
Annie Zillow_(PDQ4)
Annie Applegate_(PDQ4)`
!! Unsorted
<$list filter="[<names>splitregexp[\n]]" >
<<currentTiddler>><br/>
</$list>
!! Sorted
<$list filter="[<names>splitregexp[\n]] :sort:string[function[reorder.name],<currentTiddler>]" >
<<currentTiddler>> <br>
</$list>
</$let>
and the output looks like this:
Unsorted
Zebediah Zillow_(ABC5)
Zebediah Zillow_(XYZ3)
Annie Applegate_(ABC8)
Fred Flinstone_(XYZ4)
Zebediah Applegate_(PDQ4)
Wilma Flintstone_(ABC4)
Annie Applegate_(XYZ5)
Zebediah Applegate_(PDQ5)
Annie Zillow_(PDQ4)
Annie Applegate_(PDQ4)Sorted
Zebediah Zillow_(XYZ3)
Wilma Flintstone_(ABC4)
Annie Applegate_(PDQ4)
Zebediah Applegate_(PDQ4)
Annie Zillow_(PDQ4)
Fred Flinstone_(XYZ4)
Zebediah Zillow_(ABC5)
Zebediah Applegate_(PDQ5)
Annie Applegate_(XYZ5)
Annie Applegate_(ABC8)
You can play with it by downloading this and dragging the resulting file on any tiddlywiki: Complex Sort.json (1.3 KB)
Frankly, I see the Egg of Columbus pattern here. If you have Name.Surname_(SAK3) in a tiddler, but want to sort by SAK3, perhaps you should comb your data first? As in refactor your data and extract the SAK3 part into a field or a tag of the same tiddler, then sort by it?
I totaly agree, why use compound values where fields are available and they need not be split/parsed.
Thank you, @Scott_Sauyet and @jacng , you saved my day. A tricky riddle and a big investment of time that will pay out in the long run.