Sorting a comma-separated list with LaTeX?












11














Is there a simple way to sort a comma separated list alphabetically in LaTeX? I tried to write a macro (sortlist{World, Hello} → "Hello, World") using the l3sort documentation example but it completely failed.



ExplSyntaxOn
def@sortlist{}
newcommand{sortlist}[1]{
clist_set:Nn l_foo_clist {#1}
clist_sort:Nn l_foo_clist{
int_compare:nNnTF { ##1 } > { ##2 }
{ sort_return_swapped: }
{ sort_return_same: }
}
def@sortlist{l_foo_clist}
}
ExplSyntaxOff


Is there something like str_compare to make a string comparison or can l3sort actually only be used for numerical values?



Edit:
How to process a comma separated list? wasn't really helpful for me or rather I wasn't able to solve my problem thereby.










share|improve this question




















  • 3




    Welcome to TeX.SX! Knowing a bit more about your failed attempt and the kind of data you need to sort would be helpful.
    – egreg
    Oct 11 '16 at 11:30






  • 1




    Sorting strings of ASCII characters is feasible (although non yet supported by expl3); it would become much more complicated if words with accents and so on are involved.
    – egreg
    Oct 11 '16 at 12:37
















11














Is there a simple way to sort a comma separated list alphabetically in LaTeX? I tried to write a macro (sortlist{World, Hello} → "Hello, World") using the l3sort documentation example but it completely failed.



ExplSyntaxOn
def@sortlist{}
newcommand{sortlist}[1]{
clist_set:Nn l_foo_clist {#1}
clist_sort:Nn l_foo_clist{
int_compare:nNnTF { ##1 } > { ##2 }
{ sort_return_swapped: }
{ sort_return_same: }
}
def@sortlist{l_foo_clist}
}
ExplSyntaxOff


Is there something like str_compare to make a string comparison or can l3sort actually only be used for numerical values?



Edit:
How to process a comma separated list? wasn't really helpful for me or rather I wasn't able to solve my problem thereby.










share|improve this question




















  • 3




    Welcome to TeX.SX! Knowing a bit more about your failed attempt and the kind of data you need to sort would be helpful.
    – egreg
    Oct 11 '16 at 11:30






  • 1




    Sorting strings of ASCII characters is feasible (although non yet supported by expl3); it would become much more complicated if words with accents and so on are involved.
    – egreg
    Oct 11 '16 at 12:37














11












11








11


1





Is there a simple way to sort a comma separated list alphabetically in LaTeX? I tried to write a macro (sortlist{World, Hello} → "Hello, World") using the l3sort documentation example but it completely failed.



ExplSyntaxOn
def@sortlist{}
newcommand{sortlist}[1]{
clist_set:Nn l_foo_clist {#1}
clist_sort:Nn l_foo_clist{
int_compare:nNnTF { ##1 } > { ##2 }
{ sort_return_swapped: }
{ sort_return_same: }
}
def@sortlist{l_foo_clist}
}
ExplSyntaxOff


Is there something like str_compare to make a string comparison or can l3sort actually only be used for numerical values?



Edit:
How to process a comma separated list? wasn't really helpful for me or rather I wasn't able to solve my problem thereby.










share|improve this question















Is there a simple way to sort a comma separated list alphabetically in LaTeX? I tried to write a macro (sortlist{World, Hello} → "Hello, World") using the l3sort documentation example but it completely failed.



ExplSyntaxOn
def@sortlist{}
newcommand{sortlist}[1]{
clist_set:Nn l_foo_clist {#1}
clist_sort:Nn l_foo_clist{
int_compare:nNnTF { ##1 } > { ##2 }
{ sort_return_swapped: }
{ sort_return_same: }
}
def@sortlist{l_foo_clist}
}
ExplSyntaxOff


Is there something like str_compare to make a string comparison or can l3sort actually only be used for numerical values?



Edit:
How to process a comma separated list? wasn't really helpful for me or rather I wasn't able to solve my problem thereby.







expl3 sorting comma-separated-list






share|improve this question















share|improve this question













share|improve this question




share|improve this question








edited 7 mins ago









tambre

1668




1668










asked Oct 11 '16 at 11:23









John

585




585








  • 3




    Welcome to TeX.SX! Knowing a bit more about your failed attempt and the kind of data you need to sort would be helpful.
    – egreg
    Oct 11 '16 at 11:30






  • 1




    Sorting strings of ASCII characters is feasible (although non yet supported by expl3); it would become much more complicated if words with accents and so on are involved.
    – egreg
    Oct 11 '16 at 12:37














  • 3




    Welcome to TeX.SX! Knowing a bit more about your failed attempt and the kind of data you need to sort would be helpful.
    – egreg
    Oct 11 '16 at 11:30






  • 1




    Sorting strings of ASCII characters is feasible (although non yet supported by expl3); it would become much more complicated if words with accents and so on are involved.
    – egreg
    Oct 11 '16 at 12:37








3




3




Welcome to TeX.SX! Knowing a bit more about your failed attempt and the kind of data you need to sort would be helpful.
– egreg
Oct 11 '16 at 11:30




Welcome to TeX.SX! Knowing a bit more about your failed attempt and the kind of data you need to sort would be helpful.
– egreg
Oct 11 '16 at 11:30




1




1




Sorting strings of ASCII characters is feasible (although non yet supported by expl3); it would become much more complicated if words with accents and so on are involved.
– egreg
Oct 11 '16 at 12:37




Sorting strings of ASCII characters is feasible (although non yet supported by expl3); it would become much more complicated if words with accents and so on are involved.
– egreg
Oct 11 '16 at 12:37










4 Answers
4






active

oldest

votes


















11














This seems to work, with no packages. EDITED to solve the upper/lower-case problem.



EDIT: Resolved problem when a comparison ran out of letters prior to resolving the order, for example, wash, washer.



See ADDENDUM for handling (after a fashion) diacritics.



documentclass{article}
deflistterminator{;}
makeatletter
newcommandalphabubblesort[1]{defpresorted{}defsortedlist{}%
sortlist#1,listterminator,relax}
defsortlist#1#2,#3#4,#5relax{%
iflistterminator#3#4relax%
edefsortedlist{sortedlist#1#2}%
else
ifnumthelccode`#1<thelccode`#3relax%
edefsortedlist{sortedlistpresorted#1#2, }%
expandafterdefexpandaftersvfirstexpandafter{presorted#3#4}%
defpresorted{}%
expandaftersortlistsvfirst,#5relax%
else%
ifnum`#1=`#3relax%
ifxrelax#2relax%
edefsortedlist{sortedlistpresorted#1#2, }%
expandafterdefexpandaftersvfirstexpandafter{presorted#3#4}%
defpresorted{}%
expandaftersortlistsvfirst,#5relax%
else%
ifxrelax#4relax%
edefsortedlist{sortedlistpresorted#3#4, }%
expandafterdefexpandaftersvfirstexpandafter{presorted#1#2}%
defpresorted{}%
expandaftersortlistsvfirst,#5relax%
else
g@addto@macropresorted{#1}%
sortlist#2,#4,#5relax%
fi%
fi%
else%
lettmpsortedlist%
defsortedlist{}%
expandafterdefexpandaftersvfirstexpandafter{presorted#3#4}%
expandafterdefexpandaftersvsecondexpandafter{presorted#1#2}%
defpresorted{}%
expandafterexpandafterexpandafterexpandafterexpandafter%
expandafterexpandaftersortlistexpandafterexpandafter%
expandaftertmpexpandaftersvfirstexpandafter,svsecond,#5relax%
fi%
fi%
fi%
}
makeatother
begin{document}
alphabubblesort{book, boot, boat,toad,attic,wish,wash,wasn't,Cat ,Xylophone}
sortedlistpar

alphabubblesort{book, washer, boot, boat,toad,attic,wish,wash,wasn't,Cat ,Xylophone}
sortedlistpar
end{document}


enter image description here



ADDENDUM



Here's a version that can handle diacritics, in the sense that they do not break the algorithm. This was accomplished by changing the edefs in the above algorithm to appropriately expanded defs.



However, diacritics here will always precede all non-diacritic letters in the sort. While maybe not the ideal behavior, it may still be useful.



documentclass{article}
deflistterminator{;}
makeatletter
newcommandalphabubblesort[1]{defpresorted{}defsortedlist{}%
sortlist#1,listterminator,relax}
defsortlist#1#2,#3#4,#5relax{%
iflistterminator#3#4relax%
expandafterdefexpandaftersortedlistexpandafter{sortedlist#1#2}%
else
ifnumthelccode`#1<thelccode`#3relax%
expandafterexpandafterexpandafterdefexpandafterexpandafter%
expandaftersortedlistexpandafterexpandafterexpandafter{%
expandaftersortedlistpresorted#1#2, }%
expandafterdefexpandaftersvfirstexpandafter{presorted#3#4}%
defpresorted{}%
expandaftersortlistsvfirst,#5relax%
else%
ifnum`#1=`#3relax%
ifxrelax#2relax%
expandafterexpandafterexpandafterdefexpandafterexpandafter%
expandaftersortedlistexpandafterexpandafterexpandafter{%
expandaftersortedlistpresorted#1#2, }%
expandafterdefexpandaftersvfirstexpandafter{presorted#3#4}%
defpresorted{}%
expandaftersortlistsvfirst,#5relax%
else%
ifxrelax#4relax%
expandafterexpandafterexpandafterdefexpandafterexpandafter%
expandaftersortedlistexpandafterexpandafterexpandafter{%
expandaftersortedlistpresorted#3#4, }%
expandafterdefexpandaftersvfirstexpandafter{presorted#1#2}%
defpresorted{}%
expandaftersortlistsvfirst,#5relax%
else
g@addto@macropresorted{#1}%
sortlist#2,#4,#5relax%
fi%
fi%
else%
lettmpsortedlist%
defsortedlist{}%
expandafterdefexpandaftersvfirstexpandafter{presorted#3#4}%
expandafterdefexpandaftersvsecondexpandafter{presorted#1#2}%
defpresorted{}%
expandafterexpandafterexpandafterexpandafterexpandafter%
expandafterexpandaftersortlistexpandafterexpandafter%
expandaftertmpexpandaftersvfirstexpandafter,svsecond,#5relax%
fi%
fi%
fi%
}
makeatother
begin{document}
alphabubblesort{book, washer, w"asher, boot, boat,toad,attic,wish,wash,wasn't,
Cat, Xylophone, w"ash, edifice, 'edifice, w"asherei}
sortedlistpar
end{document}


enter image description here



The algorithm was based on my bubblesort macro here: Using LaTeX to compact a list of numbers






share|improve this answer



















  • 4




    No stackengine: boo hiss. ;-)
    – JPi
    Oct 11 '16 at 13:40






  • 2




    @JPi I know... it hurts, doesn't it.
    – Steven B. Segletes
    Oct 11 '16 at 14:29



















13














How about Lua?



defsortlist#1{%
directlua{%
local t = { #1 }
table.sort(t)
tex.sprint(table.concat(t,", "))
}%
}

sortlist{"World", "Hello"}

bye


enter image description here



Addendum: One of the really useful advantages of this approach is that it is fully expandable, meaning that after



edefx{sortlist{"World", "Hello"}}


the macro x will contain the sorted list.





When using ConTeXt MKIV you can use the internal settings parser to convert a comma separated list to a Lua table. This has the advantage that you don't need to handle quotes yourself. It also respects grouping with commas inside.



defsortlist#1{%
ctxlua{%
local t = utilities.parsers.settings_to_array("luaescapestring{#1}")
table.sort(t)
tex.sprint(table.concat(t,", "))
}%
}

starttext
sortlist{World, Hello, {Entry, with, commas}, "Quotes"}
stoptext


enter image description here






share|improve this answer























  • We (the TeX community) should definitely start a list of "generic" lua modules / functions, written for context, that could be easily used with other formats (à la luaotfload) with a wrapper. No need to reinvent the wheel.
    – cjorssen
    Oct 12 '16 at 8:34



















7














You can safely compare strings consisting of ASCII characters; words with accented characters will not work.



documentclass{article}
usepackage{expl3,l3sort,xparse}

ExplSyntaxOn
prg_new_conditional:Nnn john_string_if_before:nn { p,T,F,TF }
{% I hope the LaTeX3 police won't catch me
int_compare:nTF { pdftex_strcmp:D { #1 } { #2 } < 0 }
{
prg_return_true:
}
{
prg_return_false:
}
}

NewDocumentCommand{sortlist}{smm}
{
IfBooleanTF{#1}
{
clist_set:No l__john_sortlist_data_clist { #2 }
}
{
clist_set:Nn l__john_sortlist_data_clist { #2 }
}
john_sortlist:N l__john_sortlist_data_clist
clist_set_eq:NN #3 l__john_sortlist_data_clist
}
clist_new:N l__john_sortlist_data_clist

cs_new_protected:Nn john_sortlist:N
{
clist_sort:Nn #1
{
john_string_if_before:nnTF { ##1 } { ##2 }
{
sort_ordered:
}
{
sort_reversed:
}
}
}
ExplSyntaxOff

begin{document}

sortlist{World,Hello}{mylistA}

mylistA

newcommand{mylistB}{duck,cat,dog}

sortlist*{mylistB}{mylistC}

mylistB ${}to{}$mylistC

end{document}


enter image description here



If you want that the comparison is case insensitive, change the definition of john_sortlist:N into



cs_new_protected:Nn john_sortlist:N
{
clist_sort:Nn #1
{
john_string_if_before:nnTF { str_lower_case:n {##1} } { str_lower_case:n {##2} }
{
sort_ordered:
}
{
sort_reversed:
}
}
}




share































    1














    You can try this



    This is taken over from https://tex.stackexchange.com/a/273084/4686 (code 5)



    % ------------------------------------------------------------------
    % Expandable routine to sort strings, based on a QuickSort algorithm
    % and using pdfstrcmp.
    % ------------------------------------------------------------------

    % USAGE
    % -----

    % if using XeTeX:
    % edefmysortedlist {QSfull{mylist}}, or explicit QSfull {foo, bar, zoo}


    % if using PDFLaTeX: (and inputenc for accented letters)
    % begingroup
    % subdueutfviiienc
    % globaledefmysortedlist {QSfull{mylist}}
    % endgroup


    documentclass{article}

    ifdefinedXeTeXinterchartoks
    letpdfstrcmpstrcmp
    usepackage{fontspec}
    else
    usepackage[T1]{fontenc}
    usepackage[utf8]{inputenc}% for PDFLaTeX
    makeatletter
    % this subdueutfviiienc allows é, à, etc... to survive as is to edef's.
    newcommand*subdueutfviiienc {% to be used in a group
    count@="C2
    loop
    lccode`~count@
    lowercase{def~####1{noexpand~string####1}}%
    ifnumcount@<"E0
    advancecount@@ne
    repeat
    loop
    lccode`~count@
    lowercase{def~####1####2{noexpand~string####1string####2}}%
    ifnumcount@<"F0
    advancecount@@ne
    repeat
    loop
    lccode`~count@
    lowercase{def~####1####2####3{noexpand~string####1string####2string####3}}%
    ifnumcount@<"F4
    advancecount@@ne
    repeat
    }makeatother
    % (if inputenc is used with 8bit encoding another approach would be needed)
    fi



    % CODE TAKEN FROM https://tex.stackexchange.com/a/273084/4686 (code 5)
    % -------------------------------------------------------------------

    makeatletter
    longdefxintdothis #1#2xintorthat #3{fi #1}%
    letxintorthat @firstofone
    %
    % use some (improbable) tokens as delimiters
    catcode`! 3
    catcode`? 3
    catcode`; 3
    %
    % first we check if empty list (else qsfull@finish will not find a comma)
    % we apply f-expansion to the argument to allow it to be a macro.
    %
    defQSfull #1{expandafterqsfull@aromannumeral-`0#1,!,?}%
    %
    % first check if input has only blanks, or is empty
    defqsfull@a #1{ifx,#1xintdothisqsfull@afi
    ifx!#1xintdothisqsfull@abortfi
    xintorthat{qsfull@start #1}}%
    defqsfull@abort #1?{}%
    %
    defqsfull@start {expandafterqsfull@finishromannumeral0qsfull@b,}%
    defqsfull@finish ,#1{#1}% remove initial ,<space>

    defqsfull@b ,#1#2,#3{ifx?#3xintdothisqsfull@emptylistfi
    ifx!#3xintdothisqsfull@singletonfi
    xintorthat qsfull@separate@a {}{}#1#2;#3}%
    defqsfull@emptylist #1?{}%
    defqsfull@singleton #1#2#3;!,?{, #3}%
    %
    defqsfull@separate@a #1#2#3;#4#5,%
    % first pass, remove blanks in passing.
    % no need to be extra efficient for that.
    {%
    ifx,#4expandafterqsfull@valueisblankfi
    ifx!#4expandafterqsfull@separate@donefi
    if1pdfstrcmp{#4#5}{#3}%
    expandafterqsfull@separate@a@appendtogreater
    elseexpandafterqsfull@separate@a@appendtosmaller
    fi
    #4#5?{#1}{#2}#3;%
    }%
    defqsfull@valueisblank ifx#1fi,#2?#3#4#5;{qsfull@separate@a {#3}{#4}#5;#2,}%
    defqsfull@separate@a@appendtogreater #1?#2{qsfull@separate@a {#2, #1}}%
    %
    defqsfull@separate@a@appendtosmaller #1?#2#3{qsfull@separate@a {#2}{#3, #1}}%
    %
    defqsfull@separate@doneif#1fi #2?#3#4#5;?%
    {%
    qsfull@c #4,!,?, #5qsfull@c #3,!,?%
    }%
    % Now that the first pass is done, there are no more blank items.
    % In particular here.
    defqsfull@c ,#1#2,#3{ifx?#3xintdothisqsfull@emptylistfi
    ifx!#3xintdothisqsfull@singletonfi
    xintorthat qsfull@separate {}{}#1#2;#3}%
    %
    defqsfull@separate #1#2#3;#4#5,% blanks have already been filtered out.
    {%
    ifx!#4expandafterqsfull@separate@donefi
    if1pdfstrcmp{#4#5}{#3}%
    expandafterqsfull@separate@a@appendtogreater
    elseexpandafterqsfull@separate@a@appendtosmaller
    fi
    #4#5?{#1}{#2}#3;%
    }%
    defqsfull@separate@appendtogreater #1?#2{qsfull@separate {#2, #1}}%
    defqsfull@separate@appendtosmaller #1?#2#3{qsfull@separate {#2}{#3, #1}}%
    %
    %
    catcode`! 12
    catcode`? 12
    catcode`; 12
    makeatother


    begin{document}

    defmylist{book, washer, wäsher, boot, boat,toad,attic,wish,wash,wasn't,
    Cat, Xylophone, wäsh, edifice, édifice, wäsherei}

    % use either a macro mylist or explicit list as QSfull argument.
    ifdefinedXeTeXinterchartoks
    edefmysortedlist{QSfull{mylist}}
    else
    {subdueutfviiiencglobaledefmysortedlist{QSfull{mylist}}}%
    fi

    mylistpar

    medskip

    becomes (notice how whitespaces are normalized in the process):

    medskip

    mysortedlist

    medskip
    For some reason due to the comparison being done by verb|pdfstrcmp| the é
    comes after a-z.

    % check
    typeout{meaningmylist}

    typeout{meaningmysortedlist}

    end{document}


    enter image description here



    Here in the log output, with PDFLaTeX:



    macro:->book, washer, wäsher, boot, boat,toad,attic,wish,wash,wasn't, Cat, Xyl
    ophone, wäsh, edifice, édifice, wäsherei
    macro:->Cat, Xylophone, attic, boat, book, boot, edifice, toad, wash, washer, w
    asn't, wish, wäsh, wäsher, wäsherei, édifice


    and using XeLaTeX (which does not cut lines the same way):



    macro:->book, washer, wäsher, boot, boat,toad,attic,wish,wash,wasn't, Cat, Xylo
    phone, wäsh, edifice, édifice, wäsherei
    macro:->Cat, Xylophone, attic, boat, book, boot, edifice, toad, wash, washer, w
    asn't, wish, wäsh, wäsher, wäsherei, édifice


    The console output (again XeLaTeX) is still different, lines not cut:



    macro:->book, washer, wäsher, boot, boat,toad,attic,wish,wash,wasn't, Cat, Xylophone, wäsh, edifice, édifice, wäsherei
    macro:->Cat, Xylophone, attic, boat, book, boot, edifice, toad, wash, washer, wasn't, wish, wäsh, wäsher, wäsherei, édifice





    share|improve this answer























    • The complications with inputenc-made active characters are due to the fact we need edef to get complete expansion. But the coding could be modified to achieve complete expansion under repeated expansion of first token. In fact code 3 et 4 of tex.stackexchange.com/a/273084/4686 do that. Then no need for subdueutfviiienc.
      – jfbu
      Oct 12 '16 at 9:51











    Your Answer








    StackExchange.ready(function() {
    var channelOptions = {
    tags: "".split(" "),
    id: "85"
    };
    initTagRenderer("".split(" "), "".split(" "), channelOptions);

    StackExchange.using("externalEditor", function() {
    // Have to fire editor after snippets, if snippets enabled
    if (StackExchange.settings.snippets.snippetsEnabled) {
    StackExchange.using("snippets", function() {
    createEditor();
    });
    }
    else {
    createEditor();
    }
    });

    function createEditor() {
    StackExchange.prepareEditor({
    heartbeatType: 'answer',
    autoActivateHeartbeat: false,
    convertImagesToLinks: false,
    noModals: true,
    showLowRepImageUploadWarning: true,
    reputationToPostImages: null,
    bindNavPrevention: true,
    postfix: "",
    imageUploader: {
    brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
    contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/3.0/"u003ecc by-sa 3.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
    allowUrls: true
    },
    onDemand: true,
    discardSelector: ".discard-answer"
    ,immediatelyShowMarkdownHelp:true
    });


    }
    });














    draft saved

    draft discarded


















    StackExchange.ready(
    function () {
    StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2ftex.stackexchange.com%2fquestions%2f333646%2fsorting-a-comma-separated-list-with-latex%23new-answer', 'question_page');
    }
    );

    Post as a guest















    Required, but never shown

























    4 Answers
    4






    active

    oldest

    votes








    4 Answers
    4






    active

    oldest

    votes









    active

    oldest

    votes






    active

    oldest

    votes









    11














    This seems to work, with no packages. EDITED to solve the upper/lower-case problem.



    EDIT: Resolved problem when a comparison ran out of letters prior to resolving the order, for example, wash, washer.



    See ADDENDUM for handling (after a fashion) diacritics.



    documentclass{article}
    deflistterminator{;}
    makeatletter
    newcommandalphabubblesort[1]{defpresorted{}defsortedlist{}%
    sortlist#1,listterminator,relax}
    defsortlist#1#2,#3#4,#5relax{%
    iflistterminator#3#4relax%
    edefsortedlist{sortedlist#1#2}%
    else
    ifnumthelccode`#1<thelccode`#3relax%
    edefsortedlist{sortedlistpresorted#1#2, }%
    expandafterdefexpandaftersvfirstexpandafter{presorted#3#4}%
    defpresorted{}%
    expandaftersortlistsvfirst,#5relax%
    else%
    ifnum`#1=`#3relax%
    ifxrelax#2relax%
    edefsortedlist{sortedlistpresorted#1#2, }%
    expandafterdefexpandaftersvfirstexpandafter{presorted#3#4}%
    defpresorted{}%
    expandaftersortlistsvfirst,#5relax%
    else%
    ifxrelax#4relax%
    edefsortedlist{sortedlistpresorted#3#4, }%
    expandafterdefexpandaftersvfirstexpandafter{presorted#1#2}%
    defpresorted{}%
    expandaftersortlistsvfirst,#5relax%
    else
    g@addto@macropresorted{#1}%
    sortlist#2,#4,#5relax%
    fi%
    fi%
    else%
    lettmpsortedlist%
    defsortedlist{}%
    expandafterdefexpandaftersvfirstexpandafter{presorted#3#4}%
    expandafterdefexpandaftersvsecondexpandafter{presorted#1#2}%
    defpresorted{}%
    expandafterexpandafterexpandafterexpandafterexpandafter%
    expandafterexpandaftersortlistexpandafterexpandafter%
    expandaftertmpexpandaftersvfirstexpandafter,svsecond,#5relax%
    fi%
    fi%
    fi%
    }
    makeatother
    begin{document}
    alphabubblesort{book, boot, boat,toad,attic,wish,wash,wasn't,Cat ,Xylophone}
    sortedlistpar

    alphabubblesort{book, washer, boot, boat,toad,attic,wish,wash,wasn't,Cat ,Xylophone}
    sortedlistpar
    end{document}


    enter image description here



    ADDENDUM



    Here's a version that can handle diacritics, in the sense that they do not break the algorithm. This was accomplished by changing the edefs in the above algorithm to appropriately expanded defs.



    However, diacritics here will always precede all non-diacritic letters in the sort. While maybe not the ideal behavior, it may still be useful.



    documentclass{article}
    deflistterminator{;}
    makeatletter
    newcommandalphabubblesort[1]{defpresorted{}defsortedlist{}%
    sortlist#1,listterminator,relax}
    defsortlist#1#2,#3#4,#5relax{%
    iflistterminator#3#4relax%
    expandafterdefexpandaftersortedlistexpandafter{sortedlist#1#2}%
    else
    ifnumthelccode`#1<thelccode`#3relax%
    expandafterexpandafterexpandafterdefexpandafterexpandafter%
    expandaftersortedlistexpandafterexpandafterexpandafter{%
    expandaftersortedlistpresorted#1#2, }%
    expandafterdefexpandaftersvfirstexpandafter{presorted#3#4}%
    defpresorted{}%
    expandaftersortlistsvfirst,#5relax%
    else%
    ifnum`#1=`#3relax%
    ifxrelax#2relax%
    expandafterexpandafterexpandafterdefexpandafterexpandafter%
    expandaftersortedlistexpandafterexpandafterexpandafter{%
    expandaftersortedlistpresorted#1#2, }%
    expandafterdefexpandaftersvfirstexpandafter{presorted#3#4}%
    defpresorted{}%
    expandaftersortlistsvfirst,#5relax%
    else%
    ifxrelax#4relax%
    expandafterexpandafterexpandafterdefexpandafterexpandafter%
    expandaftersortedlistexpandafterexpandafterexpandafter{%
    expandaftersortedlistpresorted#3#4, }%
    expandafterdefexpandaftersvfirstexpandafter{presorted#1#2}%
    defpresorted{}%
    expandaftersortlistsvfirst,#5relax%
    else
    g@addto@macropresorted{#1}%
    sortlist#2,#4,#5relax%
    fi%
    fi%
    else%
    lettmpsortedlist%
    defsortedlist{}%
    expandafterdefexpandaftersvfirstexpandafter{presorted#3#4}%
    expandafterdefexpandaftersvsecondexpandafter{presorted#1#2}%
    defpresorted{}%
    expandafterexpandafterexpandafterexpandafterexpandafter%
    expandafterexpandaftersortlistexpandafterexpandafter%
    expandaftertmpexpandaftersvfirstexpandafter,svsecond,#5relax%
    fi%
    fi%
    fi%
    }
    makeatother
    begin{document}
    alphabubblesort{book, washer, w"asher, boot, boat,toad,attic,wish,wash,wasn't,
    Cat, Xylophone, w"ash, edifice, 'edifice, w"asherei}
    sortedlistpar
    end{document}


    enter image description here



    The algorithm was based on my bubblesort macro here: Using LaTeX to compact a list of numbers






    share|improve this answer



















    • 4




      No stackengine: boo hiss. ;-)
      – JPi
      Oct 11 '16 at 13:40






    • 2




      @JPi I know... it hurts, doesn't it.
      – Steven B. Segletes
      Oct 11 '16 at 14:29
















    11














    This seems to work, with no packages. EDITED to solve the upper/lower-case problem.



    EDIT: Resolved problem when a comparison ran out of letters prior to resolving the order, for example, wash, washer.



    See ADDENDUM for handling (after a fashion) diacritics.



    documentclass{article}
    deflistterminator{;}
    makeatletter
    newcommandalphabubblesort[1]{defpresorted{}defsortedlist{}%
    sortlist#1,listterminator,relax}
    defsortlist#1#2,#3#4,#5relax{%
    iflistterminator#3#4relax%
    edefsortedlist{sortedlist#1#2}%
    else
    ifnumthelccode`#1<thelccode`#3relax%
    edefsortedlist{sortedlistpresorted#1#2, }%
    expandafterdefexpandaftersvfirstexpandafter{presorted#3#4}%
    defpresorted{}%
    expandaftersortlistsvfirst,#5relax%
    else%
    ifnum`#1=`#3relax%
    ifxrelax#2relax%
    edefsortedlist{sortedlistpresorted#1#2, }%
    expandafterdefexpandaftersvfirstexpandafter{presorted#3#4}%
    defpresorted{}%
    expandaftersortlistsvfirst,#5relax%
    else%
    ifxrelax#4relax%
    edefsortedlist{sortedlistpresorted#3#4, }%
    expandafterdefexpandaftersvfirstexpandafter{presorted#1#2}%
    defpresorted{}%
    expandaftersortlistsvfirst,#5relax%
    else
    g@addto@macropresorted{#1}%
    sortlist#2,#4,#5relax%
    fi%
    fi%
    else%
    lettmpsortedlist%
    defsortedlist{}%
    expandafterdefexpandaftersvfirstexpandafter{presorted#3#4}%
    expandafterdefexpandaftersvsecondexpandafter{presorted#1#2}%
    defpresorted{}%
    expandafterexpandafterexpandafterexpandafterexpandafter%
    expandafterexpandaftersortlistexpandafterexpandafter%
    expandaftertmpexpandaftersvfirstexpandafter,svsecond,#5relax%
    fi%
    fi%
    fi%
    }
    makeatother
    begin{document}
    alphabubblesort{book, boot, boat,toad,attic,wish,wash,wasn't,Cat ,Xylophone}
    sortedlistpar

    alphabubblesort{book, washer, boot, boat,toad,attic,wish,wash,wasn't,Cat ,Xylophone}
    sortedlistpar
    end{document}


    enter image description here



    ADDENDUM



    Here's a version that can handle diacritics, in the sense that they do not break the algorithm. This was accomplished by changing the edefs in the above algorithm to appropriately expanded defs.



    However, diacritics here will always precede all non-diacritic letters in the sort. While maybe not the ideal behavior, it may still be useful.



    documentclass{article}
    deflistterminator{;}
    makeatletter
    newcommandalphabubblesort[1]{defpresorted{}defsortedlist{}%
    sortlist#1,listterminator,relax}
    defsortlist#1#2,#3#4,#5relax{%
    iflistterminator#3#4relax%
    expandafterdefexpandaftersortedlistexpandafter{sortedlist#1#2}%
    else
    ifnumthelccode`#1<thelccode`#3relax%
    expandafterexpandafterexpandafterdefexpandafterexpandafter%
    expandaftersortedlistexpandafterexpandafterexpandafter{%
    expandaftersortedlistpresorted#1#2, }%
    expandafterdefexpandaftersvfirstexpandafter{presorted#3#4}%
    defpresorted{}%
    expandaftersortlistsvfirst,#5relax%
    else%
    ifnum`#1=`#3relax%
    ifxrelax#2relax%
    expandafterexpandafterexpandafterdefexpandafterexpandafter%
    expandaftersortedlistexpandafterexpandafterexpandafter{%
    expandaftersortedlistpresorted#1#2, }%
    expandafterdefexpandaftersvfirstexpandafter{presorted#3#4}%
    defpresorted{}%
    expandaftersortlistsvfirst,#5relax%
    else%
    ifxrelax#4relax%
    expandafterexpandafterexpandafterdefexpandafterexpandafter%
    expandaftersortedlistexpandafterexpandafterexpandafter{%
    expandaftersortedlistpresorted#3#4, }%
    expandafterdefexpandaftersvfirstexpandafter{presorted#1#2}%
    defpresorted{}%
    expandaftersortlistsvfirst,#5relax%
    else
    g@addto@macropresorted{#1}%
    sortlist#2,#4,#5relax%
    fi%
    fi%
    else%
    lettmpsortedlist%
    defsortedlist{}%
    expandafterdefexpandaftersvfirstexpandafter{presorted#3#4}%
    expandafterdefexpandaftersvsecondexpandafter{presorted#1#2}%
    defpresorted{}%
    expandafterexpandafterexpandafterexpandafterexpandafter%
    expandafterexpandaftersortlistexpandafterexpandafter%
    expandaftertmpexpandaftersvfirstexpandafter,svsecond,#5relax%
    fi%
    fi%
    fi%
    }
    makeatother
    begin{document}
    alphabubblesort{book, washer, w"asher, boot, boat,toad,attic,wish,wash,wasn't,
    Cat, Xylophone, w"ash, edifice, 'edifice, w"asherei}
    sortedlistpar
    end{document}


    enter image description here



    The algorithm was based on my bubblesort macro here: Using LaTeX to compact a list of numbers






    share|improve this answer



















    • 4




      No stackengine: boo hiss. ;-)
      – JPi
      Oct 11 '16 at 13:40






    • 2




      @JPi I know... it hurts, doesn't it.
      – Steven B. Segletes
      Oct 11 '16 at 14:29














    11












    11








    11






    This seems to work, with no packages. EDITED to solve the upper/lower-case problem.



    EDIT: Resolved problem when a comparison ran out of letters prior to resolving the order, for example, wash, washer.



    See ADDENDUM for handling (after a fashion) diacritics.



    documentclass{article}
    deflistterminator{;}
    makeatletter
    newcommandalphabubblesort[1]{defpresorted{}defsortedlist{}%
    sortlist#1,listterminator,relax}
    defsortlist#1#2,#3#4,#5relax{%
    iflistterminator#3#4relax%
    edefsortedlist{sortedlist#1#2}%
    else
    ifnumthelccode`#1<thelccode`#3relax%
    edefsortedlist{sortedlistpresorted#1#2, }%
    expandafterdefexpandaftersvfirstexpandafter{presorted#3#4}%
    defpresorted{}%
    expandaftersortlistsvfirst,#5relax%
    else%
    ifnum`#1=`#3relax%
    ifxrelax#2relax%
    edefsortedlist{sortedlistpresorted#1#2, }%
    expandafterdefexpandaftersvfirstexpandafter{presorted#3#4}%
    defpresorted{}%
    expandaftersortlistsvfirst,#5relax%
    else%
    ifxrelax#4relax%
    edefsortedlist{sortedlistpresorted#3#4, }%
    expandafterdefexpandaftersvfirstexpandafter{presorted#1#2}%
    defpresorted{}%
    expandaftersortlistsvfirst,#5relax%
    else
    g@addto@macropresorted{#1}%
    sortlist#2,#4,#5relax%
    fi%
    fi%
    else%
    lettmpsortedlist%
    defsortedlist{}%
    expandafterdefexpandaftersvfirstexpandafter{presorted#3#4}%
    expandafterdefexpandaftersvsecondexpandafter{presorted#1#2}%
    defpresorted{}%
    expandafterexpandafterexpandafterexpandafterexpandafter%
    expandafterexpandaftersortlistexpandafterexpandafter%
    expandaftertmpexpandaftersvfirstexpandafter,svsecond,#5relax%
    fi%
    fi%
    fi%
    }
    makeatother
    begin{document}
    alphabubblesort{book, boot, boat,toad,attic,wish,wash,wasn't,Cat ,Xylophone}
    sortedlistpar

    alphabubblesort{book, washer, boot, boat,toad,attic,wish,wash,wasn't,Cat ,Xylophone}
    sortedlistpar
    end{document}


    enter image description here



    ADDENDUM



    Here's a version that can handle diacritics, in the sense that they do not break the algorithm. This was accomplished by changing the edefs in the above algorithm to appropriately expanded defs.



    However, diacritics here will always precede all non-diacritic letters in the sort. While maybe not the ideal behavior, it may still be useful.



    documentclass{article}
    deflistterminator{;}
    makeatletter
    newcommandalphabubblesort[1]{defpresorted{}defsortedlist{}%
    sortlist#1,listterminator,relax}
    defsortlist#1#2,#3#4,#5relax{%
    iflistterminator#3#4relax%
    expandafterdefexpandaftersortedlistexpandafter{sortedlist#1#2}%
    else
    ifnumthelccode`#1<thelccode`#3relax%
    expandafterexpandafterexpandafterdefexpandafterexpandafter%
    expandaftersortedlistexpandafterexpandafterexpandafter{%
    expandaftersortedlistpresorted#1#2, }%
    expandafterdefexpandaftersvfirstexpandafter{presorted#3#4}%
    defpresorted{}%
    expandaftersortlistsvfirst,#5relax%
    else%
    ifnum`#1=`#3relax%
    ifxrelax#2relax%
    expandafterexpandafterexpandafterdefexpandafterexpandafter%
    expandaftersortedlistexpandafterexpandafterexpandafter{%
    expandaftersortedlistpresorted#1#2, }%
    expandafterdefexpandaftersvfirstexpandafter{presorted#3#4}%
    defpresorted{}%
    expandaftersortlistsvfirst,#5relax%
    else%
    ifxrelax#4relax%
    expandafterexpandafterexpandafterdefexpandafterexpandafter%
    expandaftersortedlistexpandafterexpandafterexpandafter{%
    expandaftersortedlistpresorted#3#4, }%
    expandafterdefexpandaftersvfirstexpandafter{presorted#1#2}%
    defpresorted{}%
    expandaftersortlistsvfirst,#5relax%
    else
    g@addto@macropresorted{#1}%
    sortlist#2,#4,#5relax%
    fi%
    fi%
    else%
    lettmpsortedlist%
    defsortedlist{}%
    expandafterdefexpandaftersvfirstexpandafter{presorted#3#4}%
    expandafterdefexpandaftersvsecondexpandafter{presorted#1#2}%
    defpresorted{}%
    expandafterexpandafterexpandafterexpandafterexpandafter%
    expandafterexpandaftersortlistexpandafterexpandafter%
    expandaftertmpexpandaftersvfirstexpandafter,svsecond,#5relax%
    fi%
    fi%
    fi%
    }
    makeatother
    begin{document}
    alphabubblesort{book, washer, w"asher, boot, boat,toad,attic,wish,wash,wasn't,
    Cat, Xylophone, w"ash, edifice, 'edifice, w"asherei}
    sortedlistpar
    end{document}


    enter image description here



    The algorithm was based on my bubblesort macro here: Using LaTeX to compact a list of numbers






    share|improve this answer














    This seems to work, with no packages. EDITED to solve the upper/lower-case problem.



    EDIT: Resolved problem when a comparison ran out of letters prior to resolving the order, for example, wash, washer.



    See ADDENDUM for handling (after a fashion) diacritics.



    documentclass{article}
    deflistterminator{;}
    makeatletter
    newcommandalphabubblesort[1]{defpresorted{}defsortedlist{}%
    sortlist#1,listterminator,relax}
    defsortlist#1#2,#3#4,#5relax{%
    iflistterminator#3#4relax%
    edefsortedlist{sortedlist#1#2}%
    else
    ifnumthelccode`#1<thelccode`#3relax%
    edefsortedlist{sortedlistpresorted#1#2, }%
    expandafterdefexpandaftersvfirstexpandafter{presorted#3#4}%
    defpresorted{}%
    expandaftersortlistsvfirst,#5relax%
    else%
    ifnum`#1=`#3relax%
    ifxrelax#2relax%
    edefsortedlist{sortedlistpresorted#1#2, }%
    expandafterdefexpandaftersvfirstexpandafter{presorted#3#4}%
    defpresorted{}%
    expandaftersortlistsvfirst,#5relax%
    else%
    ifxrelax#4relax%
    edefsortedlist{sortedlistpresorted#3#4, }%
    expandafterdefexpandaftersvfirstexpandafter{presorted#1#2}%
    defpresorted{}%
    expandaftersortlistsvfirst,#5relax%
    else
    g@addto@macropresorted{#1}%
    sortlist#2,#4,#5relax%
    fi%
    fi%
    else%
    lettmpsortedlist%
    defsortedlist{}%
    expandafterdefexpandaftersvfirstexpandafter{presorted#3#4}%
    expandafterdefexpandaftersvsecondexpandafter{presorted#1#2}%
    defpresorted{}%
    expandafterexpandafterexpandafterexpandafterexpandafter%
    expandafterexpandaftersortlistexpandafterexpandafter%
    expandaftertmpexpandaftersvfirstexpandafter,svsecond,#5relax%
    fi%
    fi%
    fi%
    }
    makeatother
    begin{document}
    alphabubblesort{book, boot, boat,toad,attic,wish,wash,wasn't,Cat ,Xylophone}
    sortedlistpar

    alphabubblesort{book, washer, boot, boat,toad,attic,wish,wash,wasn't,Cat ,Xylophone}
    sortedlistpar
    end{document}


    enter image description here



    ADDENDUM



    Here's a version that can handle diacritics, in the sense that they do not break the algorithm. This was accomplished by changing the edefs in the above algorithm to appropriately expanded defs.



    However, diacritics here will always precede all non-diacritic letters in the sort. While maybe not the ideal behavior, it may still be useful.



    documentclass{article}
    deflistterminator{;}
    makeatletter
    newcommandalphabubblesort[1]{defpresorted{}defsortedlist{}%
    sortlist#1,listterminator,relax}
    defsortlist#1#2,#3#4,#5relax{%
    iflistterminator#3#4relax%
    expandafterdefexpandaftersortedlistexpandafter{sortedlist#1#2}%
    else
    ifnumthelccode`#1<thelccode`#3relax%
    expandafterexpandafterexpandafterdefexpandafterexpandafter%
    expandaftersortedlistexpandafterexpandafterexpandafter{%
    expandaftersortedlistpresorted#1#2, }%
    expandafterdefexpandaftersvfirstexpandafter{presorted#3#4}%
    defpresorted{}%
    expandaftersortlistsvfirst,#5relax%
    else%
    ifnum`#1=`#3relax%
    ifxrelax#2relax%
    expandafterexpandafterexpandafterdefexpandafterexpandafter%
    expandaftersortedlistexpandafterexpandafterexpandafter{%
    expandaftersortedlistpresorted#1#2, }%
    expandafterdefexpandaftersvfirstexpandafter{presorted#3#4}%
    defpresorted{}%
    expandaftersortlistsvfirst,#5relax%
    else%
    ifxrelax#4relax%
    expandafterexpandafterexpandafterdefexpandafterexpandafter%
    expandaftersortedlistexpandafterexpandafterexpandafter{%
    expandaftersortedlistpresorted#3#4, }%
    expandafterdefexpandaftersvfirstexpandafter{presorted#1#2}%
    defpresorted{}%
    expandaftersortlistsvfirst,#5relax%
    else
    g@addto@macropresorted{#1}%
    sortlist#2,#4,#5relax%
    fi%
    fi%
    else%
    lettmpsortedlist%
    defsortedlist{}%
    expandafterdefexpandaftersvfirstexpandafter{presorted#3#4}%
    expandafterdefexpandaftersvsecondexpandafter{presorted#1#2}%
    defpresorted{}%
    expandafterexpandafterexpandafterexpandafterexpandafter%
    expandafterexpandaftersortlistexpandafterexpandafter%
    expandaftertmpexpandaftersvfirstexpandafter,svsecond,#5relax%
    fi%
    fi%
    fi%
    }
    makeatother
    begin{document}
    alphabubblesort{book, washer, w"asher, boot, boat,toad,attic,wish,wash,wasn't,
    Cat, Xylophone, w"ash, edifice, 'edifice, w"asherei}
    sortedlistpar
    end{document}


    enter image description here



    The algorithm was based on my bubblesort macro here: Using LaTeX to compact a list of numbers







    share|improve this answer














    share|improve this answer



    share|improve this answer








    edited Apr 13 '17 at 12:35









    Community

    1




    1










    answered Oct 11 '16 at 13:11









    Steven B. Segletes

    152k9193400




    152k9193400








    • 4




      No stackengine: boo hiss. ;-)
      – JPi
      Oct 11 '16 at 13:40






    • 2




      @JPi I know... it hurts, doesn't it.
      – Steven B. Segletes
      Oct 11 '16 at 14:29














    • 4




      No stackengine: boo hiss. ;-)
      – JPi
      Oct 11 '16 at 13:40






    • 2




      @JPi I know... it hurts, doesn't it.
      – Steven B. Segletes
      Oct 11 '16 at 14:29








    4




    4




    No stackengine: boo hiss. ;-)
    – JPi
    Oct 11 '16 at 13:40




    No stackengine: boo hiss. ;-)
    – JPi
    Oct 11 '16 at 13:40




    2




    2




    @JPi I know... it hurts, doesn't it.
    – Steven B. Segletes
    Oct 11 '16 at 14:29




    @JPi I know... it hurts, doesn't it.
    – Steven B. Segletes
    Oct 11 '16 at 14:29











    13














    How about Lua?



    defsortlist#1{%
    directlua{%
    local t = { #1 }
    table.sort(t)
    tex.sprint(table.concat(t,", "))
    }%
    }

    sortlist{"World", "Hello"}

    bye


    enter image description here



    Addendum: One of the really useful advantages of this approach is that it is fully expandable, meaning that after



    edefx{sortlist{"World", "Hello"}}


    the macro x will contain the sorted list.





    When using ConTeXt MKIV you can use the internal settings parser to convert a comma separated list to a Lua table. This has the advantage that you don't need to handle quotes yourself. It also respects grouping with commas inside.



    defsortlist#1{%
    ctxlua{%
    local t = utilities.parsers.settings_to_array("luaescapestring{#1}")
    table.sort(t)
    tex.sprint(table.concat(t,", "))
    }%
    }

    starttext
    sortlist{World, Hello, {Entry, with, commas}, "Quotes"}
    stoptext


    enter image description here






    share|improve this answer























    • We (the TeX community) should definitely start a list of "generic" lua modules / functions, written for context, that could be easily used with other formats (à la luaotfload) with a wrapper. No need to reinvent the wheel.
      – cjorssen
      Oct 12 '16 at 8:34
















    13














    How about Lua?



    defsortlist#1{%
    directlua{%
    local t = { #1 }
    table.sort(t)
    tex.sprint(table.concat(t,", "))
    }%
    }

    sortlist{"World", "Hello"}

    bye


    enter image description here



    Addendum: One of the really useful advantages of this approach is that it is fully expandable, meaning that after



    edefx{sortlist{"World", "Hello"}}


    the macro x will contain the sorted list.





    When using ConTeXt MKIV you can use the internal settings parser to convert a comma separated list to a Lua table. This has the advantage that you don't need to handle quotes yourself. It also respects grouping with commas inside.



    defsortlist#1{%
    ctxlua{%
    local t = utilities.parsers.settings_to_array("luaescapestring{#1}")
    table.sort(t)
    tex.sprint(table.concat(t,", "))
    }%
    }

    starttext
    sortlist{World, Hello, {Entry, with, commas}, "Quotes"}
    stoptext


    enter image description here






    share|improve this answer























    • We (the TeX community) should definitely start a list of "generic" lua modules / functions, written for context, that could be easily used with other formats (à la luaotfload) with a wrapper. No need to reinvent the wheel.
      – cjorssen
      Oct 12 '16 at 8:34














    13












    13








    13






    How about Lua?



    defsortlist#1{%
    directlua{%
    local t = { #1 }
    table.sort(t)
    tex.sprint(table.concat(t,", "))
    }%
    }

    sortlist{"World", "Hello"}

    bye


    enter image description here



    Addendum: One of the really useful advantages of this approach is that it is fully expandable, meaning that after



    edefx{sortlist{"World", "Hello"}}


    the macro x will contain the sorted list.





    When using ConTeXt MKIV you can use the internal settings parser to convert a comma separated list to a Lua table. This has the advantage that you don't need to handle quotes yourself. It also respects grouping with commas inside.



    defsortlist#1{%
    ctxlua{%
    local t = utilities.parsers.settings_to_array("luaescapestring{#1}")
    table.sort(t)
    tex.sprint(table.concat(t,", "))
    }%
    }

    starttext
    sortlist{World, Hello, {Entry, with, commas}, "Quotes"}
    stoptext


    enter image description here






    share|improve this answer














    How about Lua?



    defsortlist#1{%
    directlua{%
    local t = { #1 }
    table.sort(t)
    tex.sprint(table.concat(t,", "))
    }%
    }

    sortlist{"World", "Hello"}

    bye


    enter image description here



    Addendum: One of the really useful advantages of this approach is that it is fully expandable, meaning that after



    edefx{sortlist{"World", "Hello"}}


    the macro x will contain the sorted list.





    When using ConTeXt MKIV you can use the internal settings parser to convert a comma separated list to a Lua table. This has the advantage that you don't need to handle quotes yourself. It also respects grouping with commas inside.



    defsortlist#1{%
    ctxlua{%
    local t = utilities.parsers.settings_to_array("luaescapestring{#1}")
    table.sort(t)
    tex.sprint(table.concat(t,", "))
    }%
    }

    starttext
    sortlist{World, Hello, {Entry, with, commas}, "Quotes"}
    stoptext


    enter image description here







    share|improve this answer














    share|improve this answer



    share|improve this answer








    edited Oct 12 '16 at 7:25

























    answered Oct 11 '16 at 12:28









    Henri Menke

    69.8k8155260




    69.8k8155260












    • We (the TeX community) should definitely start a list of "generic" lua modules / functions, written for context, that could be easily used with other formats (à la luaotfload) with a wrapper. No need to reinvent the wheel.
      – cjorssen
      Oct 12 '16 at 8:34


















    • We (the TeX community) should definitely start a list of "generic" lua modules / functions, written for context, that could be easily used with other formats (à la luaotfload) with a wrapper. No need to reinvent the wheel.
      – cjorssen
      Oct 12 '16 at 8:34
















    We (the TeX community) should definitely start a list of "generic" lua modules / functions, written for context, that could be easily used with other formats (à la luaotfload) with a wrapper. No need to reinvent the wheel.
    – cjorssen
    Oct 12 '16 at 8:34




    We (the TeX community) should definitely start a list of "generic" lua modules / functions, written for context, that could be easily used with other formats (à la luaotfload) with a wrapper. No need to reinvent the wheel.
    – cjorssen
    Oct 12 '16 at 8:34











    7














    You can safely compare strings consisting of ASCII characters; words with accented characters will not work.



    documentclass{article}
    usepackage{expl3,l3sort,xparse}

    ExplSyntaxOn
    prg_new_conditional:Nnn john_string_if_before:nn { p,T,F,TF }
    {% I hope the LaTeX3 police won't catch me
    int_compare:nTF { pdftex_strcmp:D { #1 } { #2 } < 0 }
    {
    prg_return_true:
    }
    {
    prg_return_false:
    }
    }

    NewDocumentCommand{sortlist}{smm}
    {
    IfBooleanTF{#1}
    {
    clist_set:No l__john_sortlist_data_clist { #2 }
    }
    {
    clist_set:Nn l__john_sortlist_data_clist { #2 }
    }
    john_sortlist:N l__john_sortlist_data_clist
    clist_set_eq:NN #3 l__john_sortlist_data_clist
    }
    clist_new:N l__john_sortlist_data_clist

    cs_new_protected:Nn john_sortlist:N
    {
    clist_sort:Nn #1
    {
    john_string_if_before:nnTF { ##1 } { ##2 }
    {
    sort_ordered:
    }
    {
    sort_reversed:
    }
    }
    }
    ExplSyntaxOff

    begin{document}

    sortlist{World,Hello}{mylistA}

    mylistA

    newcommand{mylistB}{duck,cat,dog}

    sortlist*{mylistB}{mylistC}

    mylistB ${}to{}$mylistC

    end{document}


    enter image description here



    If you want that the comparison is case insensitive, change the definition of john_sortlist:N into



    cs_new_protected:Nn john_sortlist:N
    {
    clist_sort:Nn #1
    {
    john_string_if_before:nnTF { str_lower_case:n {##1} } { str_lower_case:n {##2} }
    {
    sort_ordered:
    }
    {
    sort_reversed:
    }
    }
    }




    share




























      7














      You can safely compare strings consisting of ASCII characters; words with accented characters will not work.



      documentclass{article}
      usepackage{expl3,l3sort,xparse}

      ExplSyntaxOn
      prg_new_conditional:Nnn john_string_if_before:nn { p,T,F,TF }
      {% I hope the LaTeX3 police won't catch me
      int_compare:nTF { pdftex_strcmp:D { #1 } { #2 } < 0 }
      {
      prg_return_true:
      }
      {
      prg_return_false:
      }
      }

      NewDocumentCommand{sortlist}{smm}
      {
      IfBooleanTF{#1}
      {
      clist_set:No l__john_sortlist_data_clist { #2 }
      }
      {
      clist_set:Nn l__john_sortlist_data_clist { #2 }
      }
      john_sortlist:N l__john_sortlist_data_clist
      clist_set_eq:NN #3 l__john_sortlist_data_clist
      }
      clist_new:N l__john_sortlist_data_clist

      cs_new_protected:Nn john_sortlist:N
      {
      clist_sort:Nn #1
      {
      john_string_if_before:nnTF { ##1 } { ##2 }
      {
      sort_ordered:
      }
      {
      sort_reversed:
      }
      }
      }
      ExplSyntaxOff

      begin{document}

      sortlist{World,Hello}{mylistA}

      mylistA

      newcommand{mylistB}{duck,cat,dog}

      sortlist*{mylistB}{mylistC}

      mylistB ${}to{}$mylistC

      end{document}


      enter image description here



      If you want that the comparison is case insensitive, change the definition of john_sortlist:N into



      cs_new_protected:Nn john_sortlist:N
      {
      clist_sort:Nn #1
      {
      john_string_if_before:nnTF { str_lower_case:n {##1} } { str_lower_case:n {##2} }
      {
      sort_ordered:
      }
      {
      sort_reversed:
      }
      }
      }




      share


























        7












        7








        7






        You can safely compare strings consisting of ASCII characters; words with accented characters will not work.



        documentclass{article}
        usepackage{expl3,l3sort,xparse}

        ExplSyntaxOn
        prg_new_conditional:Nnn john_string_if_before:nn { p,T,F,TF }
        {% I hope the LaTeX3 police won't catch me
        int_compare:nTF { pdftex_strcmp:D { #1 } { #2 } < 0 }
        {
        prg_return_true:
        }
        {
        prg_return_false:
        }
        }

        NewDocumentCommand{sortlist}{smm}
        {
        IfBooleanTF{#1}
        {
        clist_set:No l__john_sortlist_data_clist { #2 }
        }
        {
        clist_set:Nn l__john_sortlist_data_clist { #2 }
        }
        john_sortlist:N l__john_sortlist_data_clist
        clist_set_eq:NN #3 l__john_sortlist_data_clist
        }
        clist_new:N l__john_sortlist_data_clist

        cs_new_protected:Nn john_sortlist:N
        {
        clist_sort:Nn #1
        {
        john_string_if_before:nnTF { ##1 } { ##2 }
        {
        sort_ordered:
        }
        {
        sort_reversed:
        }
        }
        }
        ExplSyntaxOff

        begin{document}

        sortlist{World,Hello}{mylistA}

        mylistA

        newcommand{mylistB}{duck,cat,dog}

        sortlist*{mylistB}{mylistC}

        mylistB ${}to{}$mylistC

        end{document}


        enter image description here



        If you want that the comparison is case insensitive, change the definition of john_sortlist:N into



        cs_new_protected:Nn john_sortlist:N
        {
        clist_sort:Nn #1
        {
        john_string_if_before:nnTF { str_lower_case:n {##1} } { str_lower_case:n {##2} }
        {
        sort_ordered:
        }
        {
        sort_reversed:
        }
        }
        }




        share














        You can safely compare strings consisting of ASCII characters; words with accented characters will not work.



        documentclass{article}
        usepackage{expl3,l3sort,xparse}

        ExplSyntaxOn
        prg_new_conditional:Nnn john_string_if_before:nn { p,T,F,TF }
        {% I hope the LaTeX3 police won't catch me
        int_compare:nTF { pdftex_strcmp:D { #1 } { #2 } < 0 }
        {
        prg_return_true:
        }
        {
        prg_return_false:
        }
        }

        NewDocumentCommand{sortlist}{smm}
        {
        IfBooleanTF{#1}
        {
        clist_set:No l__john_sortlist_data_clist { #2 }
        }
        {
        clist_set:Nn l__john_sortlist_data_clist { #2 }
        }
        john_sortlist:N l__john_sortlist_data_clist
        clist_set_eq:NN #3 l__john_sortlist_data_clist
        }
        clist_new:N l__john_sortlist_data_clist

        cs_new_protected:Nn john_sortlist:N
        {
        clist_sort:Nn #1
        {
        john_string_if_before:nnTF { ##1 } { ##2 }
        {
        sort_ordered:
        }
        {
        sort_reversed:
        }
        }
        }
        ExplSyntaxOff

        begin{document}

        sortlist{World,Hello}{mylistA}

        mylistA

        newcommand{mylistB}{duck,cat,dog}

        sortlist*{mylistB}{mylistC}

        mylistB ${}to{}$mylistC

        end{document}


        enter image description here



        If you want that the comparison is case insensitive, change the definition of john_sortlist:N into



        cs_new_protected:Nn john_sortlist:N
        {
        clist_sort:Nn #1
        {
        john_string_if_before:nnTF { str_lower_case:n {##1} } { str_lower_case:n {##2} }
        {
        sort_ordered:
        }
        {
        sort_reversed:
        }
        }
        }





        share













        share


        share








        edited Oct 11 '16 at 13:49

























        answered Oct 11 '16 at 13:38









        egreg

        708k8618813163




        708k8618813163























            1














            You can try this



            This is taken over from https://tex.stackexchange.com/a/273084/4686 (code 5)



            % ------------------------------------------------------------------
            % Expandable routine to sort strings, based on a QuickSort algorithm
            % and using pdfstrcmp.
            % ------------------------------------------------------------------

            % USAGE
            % -----

            % if using XeTeX:
            % edefmysortedlist {QSfull{mylist}}, or explicit QSfull {foo, bar, zoo}


            % if using PDFLaTeX: (and inputenc for accented letters)
            % begingroup
            % subdueutfviiienc
            % globaledefmysortedlist {QSfull{mylist}}
            % endgroup


            documentclass{article}

            ifdefinedXeTeXinterchartoks
            letpdfstrcmpstrcmp
            usepackage{fontspec}
            else
            usepackage[T1]{fontenc}
            usepackage[utf8]{inputenc}% for PDFLaTeX
            makeatletter
            % this subdueutfviiienc allows é, à, etc... to survive as is to edef's.
            newcommand*subdueutfviiienc {% to be used in a group
            count@="C2
            loop
            lccode`~count@
            lowercase{def~####1{noexpand~string####1}}%
            ifnumcount@<"E0
            advancecount@@ne
            repeat
            loop
            lccode`~count@
            lowercase{def~####1####2{noexpand~string####1string####2}}%
            ifnumcount@<"F0
            advancecount@@ne
            repeat
            loop
            lccode`~count@
            lowercase{def~####1####2####3{noexpand~string####1string####2string####3}}%
            ifnumcount@<"F4
            advancecount@@ne
            repeat
            }makeatother
            % (if inputenc is used with 8bit encoding another approach would be needed)
            fi



            % CODE TAKEN FROM https://tex.stackexchange.com/a/273084/4686 (code 5)
            % -------------------------------------------------------------------

            makeatletter
            longdefxintdothis #1#2xintorthat #3{fi #1}%
            letxintorthat @firstofone
            %
            % use some (improbable) tokens as delimiters
            catcode`! 3
            catcode`? 3
            catcode`; 3
            %
            % first we check if empty list (else qsfull@finish will not find a comma)
            % we apply f-expansion to the argument to allow it to be a macro.
            %
            defQSfull #1{expandafterqsfull@aromannumeral-`0#1,!,?}%
            %
            % first check if input has only blanks, or is empty
            defqsfull@a #1{ifx,#1xintdothisqsfull@afi
            ifx!#1xintdothisqsfull@abortfi
            xintorthat{qsfull@start #1}}%
            defqsfull@abort #1?{}%
            %
            defqsfull@start {expandafterqsfull@finishromannumeral0qsfull@b,}%
            defqsfull@finish ,#1{#1}% remove initial ,<space>

            defqsfull@b ,#1#2,#3{ifx?#3xintdothisqsfull@emptylistfi
            ifx!#3xintdothisqsfull@singletonfi
            xintorthat qsfull@separate@a {}{}#1#2;#3}%
            defqsfull@emptylist #1?{}%
            defqsfull@singleton #1#2#3;!,?{, #3}%
            %
            defqsfull@separate@a #1#2#3;#4#5,%
            % first pass, remove blanks in passing.
            % no need to be extra efficient for that.
            {%
            ifx,#4expandafterqsfull@valueisblankfi
            ifx!#4expandafterqsfull@separate@donefi
            if1pdfstrcmp{#4#5}{#3}%
            expandafterqsfull@separate@a@appendtogreater
            elseexpandafterqsfull@separate@a@appendtosmaller
            fi
            #4#5?{#1}{#2}#3;%
            }%
            defqsfull@valueisblank ifx#1fi,#2?#3#4#5;{qsfull@separate@a {#3}{#4}#5;#2,}%
            defqsfull@separate@a@appendtogreater #1?#2{qsfull@separate@a {#2, #1}}%
            %
            defqsfull@separate@a@appendtosmaller #1?#2#3{qsfull@separate@a {#2}{#3, #1}}%
            %
            defqsfull@separate@doneif#1fi #2?#3#4#5;?%
            {%
            qsfull@c #4,!,?, #5qsfull@c #3,!,?%
            }%
            % Now that the first pass is done, there are no more blank items.
            % In particular here.
            defqsfull@c ,#1#2,#3{ifx?#3xintdothisqsfull@emptylistfi
            ifx!#3xintdothisqsfull@singletonfi
            xintorthat qsfull@separate {}{}#1#2;#3}%
            %
            defqsfull@separate #1#2#3;#4#5,% blanks have already been filtered out.
            {%
            ifx!#4expandafterqsfull@separate@donefi
            if1pdfstrcmp{#4#5}{#3}%
            expandafterqsfull@separate@a@appendtogreater
            elseexpandafterqsfull@separate@a@appendtosmaller
            fi
            #4#5?{#1}{#2}#3;%
            }%
            defqsfull@separate@appendtogreater #1?#2{qsfull@separate {#2, #1}}%
            defqsfull@separate@appendtosmaller #1?#2#3{qsfull@separate {#2}{#3, #1}}%
            %
            %
            catcode`! 12
            catcode`? 12
            catcode`; 12
            makeatother


            begin{document}

            defmylist{book, washer, wäsher, boot, boat,toad,attic,wish,wash,wasn't,
            Cat, Xylophone, wäsh, edifice, édifice, wäsherei}

            % use either a macro mylist or explicit list as QSfull argument.
            ifdefinedXeTeXinterchartoks
            edefmysortedlist{QSfull{mylist}}
            else
            {subdueutfviiiencglobaledefmysortedlist{QSfull{mylist}}}%
            fi

            mylistpar

            medskip

            becomes (notice how whitespaces are normalized in the process):

            medskip

            mysortedlist

            medskip
            For some reason due to the comparison being done by verb|pdfstrcmp| the é
            comes after a-z.

            % check
            typeout{meaningmylist}

            typeout{meaningmysortedlist}

            end{document}


            enter image description here



            Here in the log output, with PDFLaTeX:



            macro:->book, washer, wäsher, boot, boat,toad,attic,wish,wash,wasn't, Cat, Xyl
            ophone, wäsh, edifice, édifice, wäsherei
            macro:->Cat, Xylophone, attic, boat, book, boot, edifice, toad, wash, washer, w
            asn't, wish, wäsh, wäsher, wäsherei, édifice


            and using XeLaTeX (which does not cut lines the same way):



            macro:->book, washer, wäsher, boot, boat,toad,attic,wish,wash,wasn't, Cat, Xylo
            phone, wäsh, edifice, édifice, wäsherei
            macro:->Cat, Xylophone, attic, boat, book, boot, edifice, toad, wash, washer, w
            asn't, wish, wäsh, wäsher, wäsherei, édifice


            The console output (again XeLaTeX) is still different, lines not cut:



            macro:->book, washer, wäsher, boot, boat,toad,attic,wish,wash,wasn't, Cat, Xylophone, wäsh, edifice, édifice, wäsherei
            macro:->Cat, Xylophone, attic, boat, book, boot, edifice, toad, wash, washer, wasn't, wish, wäsh, wäsher, wäsherei, édifice





            share|improve this answer























            • The complications with inputenc-made active characters are due to the fact we need edef to get complete expansion. But the coding could be modified to achieve complete expansion under repeated expansion of first token. In fact code 3 et 4 of tex.stackexchange.com/a/273084/4686 do that. Then no need for subdueutfviiienc.
              – jfbu
              Oct 12 '16 at 9:51
















            1














            You can try this



            This is taken over from https://tex.stackexchange.com/a/273084/4686 (code 5)



            % ------------------------------------------------------------------
            % Expandable routine to sort strings, based on a QuickSort algorithm
            % and using pdfstrcmp.
            % ------------------------------------------------------------------

            % USAGE
            % -----

            % if using XeTeX:
            % edefmysortedlist {QSfull{mylist}}, or explicit QSfull {foo, bar, zoo}


            % if using PDFLaTeX: (and inputenc for accented letters)
            % begingroup
            % subdueutfviiienc
            % globaledefmysortedlist {QSfull{mylist}}
            % endgroup


            documentclass{article}

            ifdefinedXeTeXinterchartoks
            letpdfstrcmpstrcmp
            usepackage{fontspec}
            else
            usepackage[T1]{fontenc}
            usepackage[utf8]{inputenc}% for PDFLaTeX
            makeatletter
            % this subdueutfviiienc allows é, à, etc... to survive as is to edef's.
            newcommand*subdueutfviiienc {% to be used in a group
            count@="C2
            loop
            lccode`~count@
            lowercase{def~####1{noexpand~string####1}}%
            ifnumcount@<"E0
            advancecount@@ne
            repeat
            loop
            lccode`~count@
            lowercase{def~####1####2{noexpand~string####1string####2}}%
            ifnumcount@<"F0
            advancecount@@ne
            repeat
            loop
            lccode`~count@
            lowercase{def~####1####2####3{noexpand~string####1string####2string####3}}%
            ifnumcount@<"F4
            advancecount@@ne
            repeat
            }makeatother
            % (if inputenc is used with 8bit encoding another approach would be needed)
            fi



            % CODE TAKEN FROM https://tex.stackexchange.com/a/273084/4686 (code 5)
            % -------------------------------------------------------------------

            makeatletter
            longdefxintdothis #1#2xintorthat #3{fi #1}%
            letxintorthat @firstofone
            %
            % use some (improbable) tokens as delimiters
            catcode`! 3
            catcode`? 3
            catcode`; 3
            %
            % first we check if empty list (else qsfull@finish will not find a comma)
            % we apply f-expansion to the argument to allow it to be a macro.
            %
            defQSfull #1{expandafterqsfull@aromannumeral-`0#1,!,?}%
            %
            % first check if input has only blanks, or is empty
            defqsfull@a #1{ifx,#1xintdothisqsfull@afi
            ifx!#1xintdothisqsfull@abortfi
            xintorthat{qsfull@start #1}}%
            defqsfull@abort #1?{}%
            %
            defqsfull@start {expandafterqsfull@finishromannumeral0qsfull@b,}%
            defqsfull@finish ,#1{#1}% remove initial ,<space>

            defqsfull@b ,#1#2,#3{ifx?#3xintdothisqsfull@emptylistfi
            ifx!#3xintdothisqsfull@singletonfi
            xintorthat qsfull@separate@a {}{}#1#2;#3}%
            defqsfull@emptylist #1?{}%
            defqsfull@singleton #1#2#3;!,?{, #3}%
            %
            defqsfull@separate@a #1#2#3;#4#5,%
            % first pass, remove blanks in passing.
            % no need to be extra efficient for that.
            {%
            ifx,#4expandafterqsfull@valueisblankfi
            ifx!#4expandafterqsfull@separate@donefi
            if1pdfstrcmp{#4#5}{#3}%
            expandafterqsfull@separate@a@appendtogreater
            elseexpandafterqsfull@separate@a@appendtosmaller
            fi
            #4#5?{#1}{#2}#3;%
            }%
            defqsfull@valueisblank ifx#1fi,#2?#3#4#5;{qsfull@separate@a {#3}{#4}#5;#2,}%
            defqsfull@separate@a@appendtogreater #1?#2{qsfull@separate@a {#2, #1}}%
            %
            defqsfull@separate@a@appendtosmaller #1?#2#3{qsfull@separate@a {#2}{#3, #1}}%
            %
            defqsfull@separate@doneif#1fi #2?#3#4#5;?%
            {%
            qsfull@c #4,!,?, #5qsfull@c #3,!,?%
            }%
            % Now that the first pass is done, there are no more blank items.
            % In particular here.
            defqsfull@c ,#1#2,#3{ifx?#3xintdothisqsfull@emptylistfi
            ifx!#3xintdothisqsfull@singletonfi
            xintorthat qsfull@separate {}{}#1#2;#3}%
            %
            defqsfull@separate #1#2#3;#4#5,% blanks have already been filtered out.
            {%
            ifx!#4expandafterqsfull@separate@donefi
            if1pdfstrcmp{#4#5}{#3}%
            expandafterqsfull@separate@a@appendtogreater
            elseexpandafterqsfull@separate@a@appendtosmaller
            fi
            #4#5?{#1}{#2}#3;%
            }%
            defqsfull@separate@appendtogreater #1?#2{qsfull@separate {#2, #1}}%
            defqsfull@separate@appendtosmaller #1?#2#3{qsfull@separate {#2}{#3, #1}}%
            %
            %
            catcode`! 12
            catcode`? 12
            catcode`; 12
            makeatother


            begin{document}

            defmylist{book, washer, wäsher, boot, boat,toad,attic,wish,wash,wasn't,
            Cat, Xylophone, wäsh, edifice, édifice, wäsherei}

            % use either a macro mylist or explicit list as QSfull argument.
            ifdefinedXeTeXinterchartoks
            edefmysortedlist{QSfull{mylist}}
            else
            {subdueutfviiiencglobaledefmysortedlist{QSfull{mylist}}}%
            fi

            mylistpar

            medskip

            becomes (notice how whitespaces are normalized in the process):

            medskip

            mysortedlist

            medskip
            For some reason due to the comparison being done by verb|pdfstrcmp| the é
            comes after a-z.

            % check
            typeout{meaningmylist}

            typeout{meaningmysortedlist}

            end{document}


            enter image description here



            Here in the log output, with PDFLaTeX:



            macro:->book, washer, wäsher, boot, boat,toad,attic,wish,wash,wasn't, Cat, Xyl
            ophone, wäsh, edifice, édifice, wäsherei
            macro:->Cat, Xylophone, attic, boat, book, boot, edifice, toad, wash, washer, w
            asn't, wish, wäsh, wäsher, wäsherei, édifice


            and using XeLaTeX (which does not cut lines the same way):



            macro:->book, washer, wäsher, boot, boat,toad,attic,wish,wash,wasn't, Cat, Xylo
            phone, wäsh, edifice, édifice, wäsherei
            macro:->Cat, Xylophone, attic, boat, book, boot, edifice, toad, wash, washer, w
            asn't, wish, wäsh, wäsher, wäsherei, édifice


            The console output (again XeLaTeX) is still different, lines not cut:



            macro:->book, washer, wäsher, boot, boat,toad,attic,wish,wash,wasn't, Cat, Xylophone, wäsh, edifice, édifice, wäsherei
            macro:->Cat, Xylophone, attic, boat, book, boot, edifice, toad, wash, washer, wasn't, wish, wäsh, wäsher, wäsherei, édifice





            share|improve this answer























            • The complications with inputenc-made active characters are due to the fact we need edef to get complete expansion. But the coding could be modified to achieve complete expansion under repeated expansion of first token. In fact code 3 et 4 of tex.stackexchange.com/a/273084/4686 do that. Then no need for subdueutfviiienc.
              – jfbu
              Oct 12 '16 at 9:51














            1












            1








            1






            You can try this



            This is taken over from https://tex.stackexchange.com/a/273084/4686 (code 5)



            % ------------------------------------------------------------------
            % Expandable routine to sort strings, based on a QuickSort algorithm
            % and using pdfstrcmp.
            % ------------------------------------------------------------------

            % USAGE
            % -----

            % if using XeTeX:
            % edefmysortedlist {QSfull{mylist}}, or explicit QSfull {foo, bar, zoo}


            % if using PDFLaTeX: (and inputenc for accented letters)
            % begingroup
            % subdueutfviiienc
            % globaledefmysortedlist {QSfull{mylist}}
            % endgroup


            documentclass{article}

            ifdefinedXeTeXinterchartoks
            letpdfstrcmpstrcmp
            usepackage{fontspec}
            else
            usepackage[T1]{fontenc}
            usepackage[utf8]{inputenc}% for PDFLaTeX
            makeatletter
            % this subdueutfviiienc allows é, à, etc... to survive as is to edef's.
            newcommand*subdueutfviiienc {% to be used in a group
            count@="C2
            loop
            lccode`~count@
            lowercase{def~####1{noexpand~string####1}}%
            ifnumcount@<"E0
            advancecount@@ne
            repeat
            loop
            lccode`~count@
            lowercase{def~####1####2{noexpand~string####1string####2}}%
            ifnumcount@<"F0
            advancecount@@ne
            repeat
            loop
            lccode`~count@
            lowercase{def~####1####2####3{noexpand~string####1string####2string####3}}%
            ifnumcount@<"F4
            advancecount@@ne
            repeat
            }makeatother
            % (if inputenc is used with 8bit encoding another approach would be needed)
            fi



            % CODE TAKEN FROM https://tex.stackexchange.com/a/273084/4686 (code 5)
            % -------------------------------------------------------------------

            makeatletter
            longdefxintdothis #1#2xintorthat #3{fi #1}%
            letxintorthat @firstofone
            %
            % use some (improbable) tokens as delimiters
            catcode`! 3
            catcode`? 3
            catcode`; 3
            %
            % first we check if empty list (else qsfull@finish will not find a comma)
            % we apply f-expansion to the argument to allow it to be a macro.
            %
            defQSfull #1{expandafterqsfull@aromannumeral-`0#1,!,?}%
            %
            % first check if input has only blanks, or is empty
            defqsfull@a #1{ifx,#1xintdothisqsfull@afi
            ifx!#1xintdothisqsfull@abortfi
            xintorthat{qsfull@start #1}}%
            defqsfull@abort #1?{}%
            %
            defqsfull@start {expandafterqsfull@finishromannumeral0qsfull@b,}%
            defqsfull@finish ,#1{#1}% remove initial ,<space>

            defqsfull@b ,#1#2,#3{ifx?#3xintdothisqsfull@emptylistfi
            ifx!#3xintdothisqsfull@singletonfi
            xintorthat qsfull@separate@a {}{}#1#2;#3}%
            defqsfull@emptylist #1?{}%
            defqsfull@singleton #1#2#3;!,?{, #3}%
            %
            defqsfull@separate@a #1#2#3;#4#5,%
            % first pass, remove blanks in passing.
            % no need to be extra efficient for that.
            {%
            ifx,#4expandafterqsfull@valueisblankfi
            ifx!#4expandafterqsfull@separate@donefi
            if1pdfstrcmp{#4#5}{#3}%
            expandafterqsfull@separate@a@appendtogreater
            elseexpandafterqsfull@separate@a@appendtosmaller
            fi
            #4#5?{#1}{#2}#3;%
            }%
            defqsfull@valueisblank ifx#1fi,#2?#3#4#5;{qsfull@separate@a {#3}{#4}#5;#2,}%
            defqsfull@separate@a@appendtogreater #1?#2{qsfull@separate@a {#2, #1}}%
            %
            defqsfull@separate@a@appendtosmaller #1?#2#3{qsfull@separate@a {#2}{#3, #1}}%
            %
            defqsfull@separate@doneif#1fi #2?#3#4#5;?%
            {%
            qsfull@c #4,!,?, #5qsfull@c #3,!,?%
            }%
            % Now that the first pass is done, there are no more blank items.
            % In particular here.
            defqsfull@c ,#1#2,#3{ifx?#3xintdothisqsfull@emptylistfi
            ifx!#3xintdothisqsfull@singletonfi
            xintorthat qsfull@separate {}{}#1#2;#3}%
            %
            defqsfull@separate #1#2#3;#4#5,% blanks have already been filtered out.
            {%
            ifx!#4expandafterqsfull@separate@donefi
            if1pdfstrcmp{#4#5}{#3}%
            expandafterqsfull@separate@a@appendtogreater
            elseexpandafterqsfull@separate@a@appendtosmaller
            fi
            #4#5?{#1}{#2}#3;%
            }%
            defqsfull@separate@appendtogreater #1?#2{qsfull@separate {#2, #1}}%
            defqsfull@separate@appendtosmaller #1?#2#3{qsfull@separate {#2}{#3, #1}}%
            %
            %
            catcode`! 12
            catcode`? 12
            catcode`; 12
            makeatother


            begin{document}

            defmylist{book, washer, wäsher, boot, boat,toad,attic,wish,wash,wasn't,
            Cat, Xylophone, wäsh, edifice, édifice, wäsherei}

            % use either a macro mylist or explicit list as QSfull argument.
            ifdefinedXeTeXinterchartoks
            edefmysortedlist{QSfull{mylist}}
            else
            {subdueutfviiiencglobaledefmysortedlist{QSfull{mylist}}}%
            fi

            mylistpar

            medskip

            becomes (notice how whitespaces are normalized in the process):

            medskip

            mysortedlist

            medskip
            For some reason due to the comparison being done by verb|pdfstrcmp| the é
            comes after a-z.

            % check
            typeout{meaningmylist}

            typeout{meaningmysortedlist}

            end{document}


            enter image description here



            Here in the log output, with PDFLaTeX:



            macro:->book, washer, wäsher, boot, boat,toad,attic,wish,wash,wasn't, Cat, Xyl
            ophone, wäsh, edifice, édifice, wäsherei
            macro:->Cat, Xylophone, attic, boat, book, boot, edifice, toad, wash, washer, w
            asn't, wish, wäsh, wäsher, wäsherei, édifice


            and using XeLaTeX (which does not cut lines the same way):



            macro:->book, washer, wäsher, boot, boat,toad,attic,wish,wash,wasn't, Cat, Xylo
            phone, wäsh, edifice, édifice, wäsherei
            macro:->Cat, Xylophone, attic, boat, book, boot, edifice, toad, wash, washer, w
            asn't, wish, wäsh, wäsher, wäsherei, édifice


            The console output (again XeLaTeX) is still different, lines not cut:



            macro:->book, washer, wäsher, boot, boat,toad,attic,wish,wash,wasn't, Cat, Xylophone, wäsh, edifice, édifice, wäsherei
            macro:->Cat, Xylophone, attic, boat, book, boot, edifice, toad, wash, washer, wasn't, wish, wäsh, wäsher, wäsherei, édifice





            share|improve this answer














            You can try this



            This is taken over from https://tex.stackexchange.com/a/273084/4686 (code 5)



            % ------------------------------------------------------------------
            % Expandable routine to sort strings, based on a QuickSort algorithm
            % and using pdfstrcmp.
            % ------------------------------------------------------------------

            % USAGE
            % -----

            % if using XeTeX:
            % edefmysortedlist {QSfull{mylist}}, or explicit QSfull {foo, bar, zoo}


            % if using PDFLaTeX: (and inputenc for accented letters)
            % begingroup
            % subdueutfviiienc
            % globaledefmysortedlist {QSfull{mylist}}
            % endgroup


            documentclass{article}

            ifdefinedXeTeXinterchartoks
            letpdfstrcmpstrcmp
            usepackage{fontspec}
            else
            usepackage[T1]{fontenc}
            usepackage[utf8]{inputenc}% for PDFLaTeX
            makeatletter
            % this subdueutfviiienc allows é, à, etc... to survive as is to edef's.
            newcommand*subdueutfviiienc {% to be used in a group
            count@="C2
            loop
            lccode`~count@
            lowercase{def~####1{noexpand~string####1}}%
            ifnumcount@<"E0
            advancecount@@ne
            repeat
            loop
            lccode`~count@
            lowercase{def~####1####2{noexpand~string####1string####2}}%
            ifnumcount@<"F0
            advancecount@@ne
            repeat
            loop
            lccode`~count@
            lowercase{def~####1####2####3{noexpand~string####1string####2string####3}}%
            ifnumcount@<"F4
            advancecount@@ne
            repeat
            }makeatother
            % (if inputenc is used with 8bit encoding another approach would be needed)
            fi



            % CODE TAKEN FROM https://tex.stackexchange.com/a/273084/4686 (code 5)
            % -------------------------------------------------------------------

            makeatletter
            longdefxintdothis #1#2xintorthat #3{fi #1}%
            letxintorthat @firstofone
            %
            % use some (improbable) tokens as delimiters
            catcode`! 3
            catcode`? 3
            catcode`; 3
            %
            % first we check if empty list (else qsfull@finish will not find a comma)
            % we apply f-expansion to the argument to allow it to be a macro.
            %
            defQSfull #1{expandafterqsfull@aromannumeral-`0#1,!,?}%
            %
            % first check if input has only blanks, or is empty
            defqsfull@a #1{ifx,#1xintdothisqsfull@afi
            ifx!#1xintdothisqsfull@abortfi
            xintorthat{qsfull@start #1}}%
            defqsfull@abort #1?{}%
            %
            defqsfull@start {expandafterqsfull@finishromannumeral0qsfull@b,}%
            defqsfull@finish ,#1{#1}% remove initial ,<space>

            defqsfull@b ,#1#2,#3{ifx?#3xintdothisqsfull@emptylistfi
            ifx!#3xintdothisqsfull@singletonfi
            xintorthat qsfull@separate@a {}{}#1#2;#3}%
            defqsfull@emptylist #1?{}%
            defqsfull@singleton #1#2#3;!,?{, #3}%
            %
            defqsfull@separate@a #1#2#3;#4#5,%
            % first pass, remove blanks in passing.
            % no need to be extra efficient for that.
            {%
            ifx,#4expandafterqsfull@valueisblankfi
            ifx!#4expandafterqsfull@separate@donefi
            if1pdfstrcmp{#4#5}{#3}%
            expandafterqsfull@separate@a@appendtogreater
            elseexpandafterqsfull@separate@a@appendtosmaller
            fi
            #4#5?{#1}{#2}#3;%
            }%
            defqsfull@valueisblank ifx#1fi,#2?#3#4#5;{qsfull@separate@a {#3}{#4}#5;#2,}%
            defqsfull@separate@a@appendtogreater #1?#2{qsfull@separate@a {#2, #1}}%
            %
            defqsfull@separate@a@appendtosmaller #1?#2#3{qsfull@separate@a {#2}{#3, #1}}%
            %
            defqsfull@separate@doneif#1fi #2?#3#4#5;?%
            {%
            qsfull@c #4,!,?, #5qsfull@c #3,!,?%
            }%
            % Now that the first pass is done, there are no more blank items.
            % In particular here.
            defqsfull@c ,#1#2,#3{ifx?#3xintdothisqsfull@emptylistfi
            ifx!#3xintdothisqsfull@singletonfi
            xintorthat qsfull@separate {}{}#1#2;#3}%
            %
            defqsfull@separate #1#2#3;#4#5,% blanks have already been filtered out.
            {%
            ifx!#4expandafterqsfull@separate@donefi
            if1pdfstrcmp{#4#5}{#3}%
            expandafterqsfull@separate@a@appendtogreater
            elseexpandafterqsfull@separate@a@appendtosmaller
            fi
            #4#5?{#1}{#2}#3;%
            }%
            defqsfull@separate@appendtogreater #1?#2{qsfull@separate {#2, #1}}%
            defqsfull@separate@appendtosmaller #1?#2#3{qsfull@separate {#2}{#3, #1}}%
            %
            %
            catcode`! 12
            catcode`? 12
            catcode`; 12
            makeatother


            begin{document}

            defmylist{book, washer, wäsher, boot, boat,toad,attic,wish,wash,wasn't,
            Cat, Xylophone, wäsh, edifice, édifice, wäsherei}

            % use either a macro mylist or explicit list as QSfull argument.
            ifdefinedXeTeXinterchartoks
            edefmysortedlist{QSfull{mylist}}
            else
            {subdueutfviiiencglobaledefmysortedlist{QSfull{mylist}}}%
            fi

            mylistpar

            medskip

            becomes (notice how whitespaces are normalized in the process):

            medskip

            mysortedlist

            medskip
            For some reason due to the comparison being done by verb|pdfstrcmp| the é
            comes after a-z.

            % check
            typeout{meaningmylist}

            typeout{meaningmysortedlist}

            end{document}


            enter image description here



            Here in the log output, with PDFLaTeX:



            macro:->book, washer, wäsher, boot, boat,toad,attic,wish,wash,wasn't, Cat, Xyl
            ophone, wäsh, edifice, édifice, wäsherei
            macro:->Cat, Xylophone, attic, boat, book, boot, edifice, toad, wash, washer, w
            asn't, wish, wäsh, wäsher, wäsherei, édifice


            and using XeLaTeX (which does not cut lines the same way):



            macro:->book, washer, wäsher, boot, boat,toad,attic,wish,wash,wasn't, Cat, Xylo
            phone, wäsh, edifice, édifice, wäsherei
            macro:->Cat, Xylophone, attic, boat, book, boot, edifice, toad, wash, washer, w
            asn't, wish, wäsh, wäsher, wäsherei, édifice


            The console output (again XeLaTeX) is still different, lines not cut:



            macro:->book, washer, wäsher, boot, boat,toad,attic,wish,wash,wasn't, Cat, Xylophone, wäsh, edifice, édifice, wäsherei
            macro:->Cat, Xylophone, attic, boat, book, boot, edifice, toad, wash, washer, wasn't, wish, wäsh, wäsher, wäsherei, édifice






            share|improve this answer














            share|improve this answer



            share|improve this answer








            edited Apr 13 '17 at 12:34









            Community

            1




            1










            answered Oct 12 '16 at 8:52









            jfbu

            46k66148




            46k66148












            • The complications with inputenc-made active characters are due to the fact we need edef to get complete expansion. But the coding could be modified to achieve complete expansion under repeated expansion of first token. In fact code 3 et 4 of tex.stackexchange.com/a/273084/4686 do that. Then no need for subdueutfviiienc.
              – jfbu
              Oct 12 '16 at 9:51


















            • The complications with inputenc-made active characters are due to the fact we need edef to get complete expansion. But the coding could be modified to achieve complete expansion under repeated expansion of first token. In fact code 3 et 4 of tex.stackexchange.com/a/273084/4686 do that. Then no need for subdueutfviiienc.
              – jfbu
              Oct 12 '16 at 9:51
















            The complications with inputenc-made active characters are due to the fact we need edef to get complete expansion. But the coding could be modified to achieve complete expansion under repeated expansion of first token. In fact code 3 et 4 of tex.stackexchange.com/a/273084/4686 do that. Then no need for subdueutfviiienc.
            – jfbu
            Oct 12 '16 at 9:51




            The complications with inputenc-made active characters are due to the fact we need edef to get complete expansion. But the coding could be modified to achieve complete expansion under repeated expansion of first token. In fact code 3 et 4 of tex.stackexchange.com/a/273084/4686 do that. Then no need for subdueutfviiienc.
            – jfbu
            Oct 12 '16 at 9:51


















            draft saved

            draft discarded




















































            Thanks for contributing an answer to TeX - LaTeX Stack Exchange!


            • Please be sure to answer the question. Provide details and share your research!

            But avoid



            • Asking for help, clarification, or responding to other answers.

            • Making statements based on opinion; back them up with references or personal experience.


            To learn more, see our tips on writing great answers.





            Some of your past answers have not been well-received, and you're in danger of being blocked from answering.


            Please pay close attention to the following guidance:


            • Please be sure to answer the question. Provide details and share your research!

            But avoid



            • Asking for help, clarification, or responding to other answers.

            • Making statements based on opinion; back them up with references or personal experience.


            To learn more, see our tips on writing great answers.




            draft saved


            draft discarded














            StackExchange.ready(
            function () {
            StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2ftex.stackexchange.com%2fquestions%2f333646%2fsorting-a-comma-separated-list-with-latex%23new-answer', 'question_page');
            }
            );

            Post as a guest















            Required, but never shown





















































            Required, but never shown














            Required, but never shown












            Required, but never shown







            Required, but never shown

































            Required, but never shown














            Required, but never shown












            Required, but never shown







            Required, but never shown







            Popular posts from this blog

            サソリ

            広島県道265号伴広島線

            Setup Asymptote in Texstudio