TransWikia.com

Alphabetical sorting of a sequence of names

TeX - LaTeX Asked on October 18, 2020

I have a long number of people to acknowledge in my thesis, and I was wondering if it would be possible to sort their names automatically, rather than doing it by hand. In other words, I would like a macro, say sorted, which would take

sorted{Gauss, Carl Friedrich and Riemann, Bernhard and Euler, Leonhard}

and output

Leonard Euler, Carl Friedrich Gauss and Bernhard Riemann

To be clear, I am not looking to sort the items in a list environment. Rather, I would like to output a sentence that contains the various names, in alphabetical order. All names but the last two should be separated by a ,, while the last two should be separated by and.

4 Answers

Is this what you want? I define some ordering rule:

  • aA: [a-zA-Z]
  • raA: [Z-Az-a]
  • Aa: [A-Za-z]
  • rAa: [z-aZ-A]

You can also define your owner ordering rule.

enter image description here

documentclass{article}
usepackage{xparse}
ExplSyntaxOn

tl_new:N l__seq_sep_tl
seq_new:N l__alph_seq
seq_new:N l__Alph_seq
seq_new:N l__Alphalpa_seq
seq_new:N l__alphAlph_seq
seq_new:N l__ralph_seq
seq_new:N l__rAlph_seq
seq_new:N l__rAlphalpa_seq
seq_new:N l__ralphAlph_seq
seq_new:N l__result_seq
seq_new:N l__custom_order_seq
bool_new:N l__if_less_bool
prop_new:N l__order_prop

seq_set_from_clist:Nn l__alph_seq
  { a,b,c,d,e,f,g,h,i,g,k,l,m,n,o,p,q,r,s,t,u,v,w,x,y,z }
seq_set_from_clist:Nn l__Alph_seq
  { A,B,C,D,E,F,G,H,I,G,K,L,M,N,O,P,Q,R,S,T,U,V,W,X,Y,Z }
seq_set_from_clist:Nn l__Alphalph_seq
  {
    A,B,C,D,E,F,G,H,I,G,K,L,M,N,O,P,Q,R,S,T,U,V,W,X,Y,Z,
    a,b,c,d,e,f,g,h,i,g,k,l,m,n,o,p,q,r,s,t,u,v,w,x,y,z
  }
seq_set_from_clist:Nn l__alphAlph_seq
  {
    a,b,c,d,e,f,g,h,i,g,k,l,m,n,o,p,q,r,s,t,u,v,w,x,y,z,
    A,B,C,D,E,F,G,H,I,G,K,L,M,N,O,P,Q,R,S,T,U,V,W,X,Y,Z
  }
seq_set_eq:NN l__ralph_seq l__alph_seq
seq_set_eq:NN l__rAlph_seq l__Alph_seq
seq_set_eq:NN l__ralphAlph_seq l__alphAlph_seq
seq_set_eq:NN l__rAlphalph_seq l__Alphalph_seq
seq_reverse:N l__ralph_seq
seq_reverse:N l__rAlph_seq
seq_reverse:N l__ralphAlph_seq
seq_reverse:N l__rAlphalph_seq
seq_set_eq:NN l__custom_order_seq l__Alphalph_seq

prop_set_from_keyval:Nn l__order_prop
  {
    a = alph,
    A = Alph,
    aA = alphAlph,
    Aa = Alphalph,
    ra = ralph,
    rA = rAlph,
    raA = ralphAlph,
    rAa = rAlphalph,
  }

keys_define:nn { sort }
  {
    order .code:n = { set_order_from_option:n { #1 } },
    sep .tl_set:N = l__seq_sep_tl,
  }

cs_new_protected:Nn set_sort_order_from_seq:N
  {
    int_zero:N l_tmpa_int
    seq_remove_duplicates:N #1
    seq_map_inline:Nn #1
      {
        int_incr:N l_tmpa_int
        int_if_exist:cF { g__sort_##1 }
          {
            int_new:c { g__sort_##1 }
          }
        int_gset_eq:cN { g__sort_##1 } l_tmpa_int
      }
  }

prg_new_protected_conditional:Nnn str_if_less:nn { T, F, TF }
  {
    int_set:Nn l_tmpa_int
      { str_count_ignore_spaces:n { #1 } }
    int_set:Nn l_tmpb_int
      { str_count_ignore_spaces:n { #2 } }
    int_compare:nTF { l_tmpa_int < l_tmpb_int }
      { bool_set_true:N l__if_less_bool }
      { bool_set_false:N l__if_less_bool }
    int_step_inline:nn { int_min:nn { l_tmpa_int } { l_tmpb_int } }
      {
        int_set_eq:Nc l_tmpa_int
          { g__sort_str_item:nn { #1 } { ##1 } }
        int_set_eq:Nc l_tmpb_int
          { g__sort_str_item:nn { #2 } { ##1 } }
        int_compare:nF { l_tmpa_int = l_tmpb_int }
          {
            int_compare:nTF { l_tmpa_int < l_tmpb_int }
              { bool_set_true:N l__if_less_bool }
              { bool_set_false:N l__if_less_bool }
            prg_break:
          }
      }
    bool_if:NTF l__if_less_bool
      { prg_return_true: }
      { prg_return_false: }
  }

% #1 seq to be sorted #2 predefined order seq
cs_new_protected:Nn seq_sort_by_order:NN
  {
    set_sort_order_from_seq:N #2
    seq_sort:Nn #1
      {
        str_if_less:nnTF { ##1 } { ##2 }
          { sort_return_same: }
          { sort_return_swapped: }
      }
  }


cs_generate_variant:Nn seq_set_split:Nnn { Nxo }
cs_new_protected:Nn sort_custom_seq:nn
  {
    keys_set:nn { sort }
      {
        sep = {,},
        #1
      }
    seq_set_split:Nxo l__result_seq { l__seq_sep_tl } { #2 }
    seq_sort_by_order:NN l__result_seq l__custom_order_seq
  }

% #1 seq handle function #2 options #3 list
cs_new_protected:Nn sort_custom_seq:Nnn
  {
    sort_custom_seq:nn { #2 } { #3 }
    #1 l__result_seq
  }

cs_new_protected:Nn my_transpose:N
  {
    seq_clear_new:N l__new_seq
    seq_map_inline:Nn #1
      {
        seq_clear_new:N l__item_seq
        seq_set_split:Nnn l__item_seq { , } { ##1 }
        seq_reverse:N l__item_seq
        seq_put_right:Nx l__new_seq { seq_use:Nn l__item_seq { ~ } }
      }
    seq_set_eq:NN #1 l__new_seq
  }

cs_new_protected:Nn set_order_from_seq:nn
  {
    seq_set_split:Nnn l__custom_order_seq { #1 } { #2 }
  }

cs_new_protected:Nn set_order_from_str:n
  {
    str_set:Nn l_tmpa_str { #1 }
    seq_clear:N l__custom_order_seq
    str_map_inline:Nn l_tmpa_str
      {
        seq_put_right:Nn l__custom_order_seq { ##1 }
      }
  }

cs_new_protected:Nn set_order_from_option:n
  {
    prop_if_in:NnTF l__order_prop { #1 }
      {
        seq_set_eq:Nc l__custom_order_seq
          { l__prop_item:Nn l__order_prop { #1 }_seq }
      }
      {
        set_order_from_str:n { #1 }
      }
  }

NewDocumentCommand { setorder } { o m }
  {
    IfNoValueTF { #1 }
      { set_order_from_str:n { #2 } }
      { set_order_from_seq:nn { #1 } { #2 } }
  }

NewDocumentCommand { mysorted } { O{} +m }
  {
    sort_custom_seq:Nnn my_transpose:N { #1 } { #2 }
    seq_use:Nnnn l__result_seq { ~and~ } { ,~ } { ~and~ }
  }

NewDocumentCommand { sorted } { m +m }
  {
    sort_custom_seq:nn { order = #1 } { #2 }
    makebox[4cm][l]{bfseries Order:~#1}
    seq_map_inline:Nn l__result_seq
      {
        makebox[1.2cm][l]{##1}
      }
  }

ExplSyntaxOff

begin{document}
mysorted[sep=and]{Gauss, Carl Friedrich and Riemann, Bernhard and Euler, Leonhard}

deftest{app, band, apple, Apple, App}
sorted{aA}{test}

sorted{raA}{test}

sorted{Aa}{test}

sorted{rAa}{test}

sorted{ab-+*@c}{abc, c@-, b+@, @cb, b-c}
end{document}

Correct answer by ZhiyuanLck on October 18, 2020

This is not a complete answer, but the question is not complete, either. As in my comment above, I am basing this answer on this question: Alphabetically display the items in itemize

I changed three lines in the preamble: in essence, there is no need to output a list, just because you input as list. I think that was your biggest issue with my comment.

documentclass{article}
usepackage{datatool}% http://ctan.org/pkg/datatool
newcommand{sortitem}[1]{%
  DTLnewrow{list}% Create a new entry
  DTLnewdbentry{list}{description}{#1}% Add entry as description
}
newenvironment{sortedlist}{%
  DTLifdbexists{list}{DTLcleardb{list}}{DTLnewdb{list}}% Create new/discard old list
}{%
  DTLsort{description}{list}% Sort list
  %begin{itemize}% THIS LINE CHANGED
    DTLforeach*{list}{theDesc=description}{%
      theDesc{} and }% THIS LINE CHANGED
  %end{itemize}% THIS LINE CHANGED
}
begin{document}

begin{sortedlist}
    sortitem{Gauss, Carl Friedrich}
    sortitem{Riemann, Bernhard}
    sortitem{Euler, Leonhard}
end{sortedlist}

end{document}

This outputs

Euler, Leonhard and Gauss, Carl Friedrich and Riemann, Bernhard and

Your remaining, implicit parts of question (output list separated by commas and "and") are probably answered in Iterating through comma-separated arguments or Special handling of first and/or last item in an etoolbox list.

Answered by bers on October 18, 2020

Bubble sorter, which I adapt from my modification to David's answer to my question at Trying to eliminate stack overflow during recursion.

The sortlist macro is the bubble sorter (from the referenced answer, but with and rather than , as the list seperator). However, it leaves the result in the form of Last Name, First and ....

I had to add the rework macro to make it First Last Name and employ whichsep to choose whether a , or and should be inserted between names, depending on their placement in the list.

No packages required!

documentclass[10pt]{article}
newcommandalphabubblesort[1]{defsortedlist{}%
  expandaftersortlist#1 and cr and relax
  expandafterreworksortedlist and relax}
defsortlist#1and #2and #3relax{%
  letnextrelax
  ifxcr#2relax%
    edefsortedlist{sortedlist#1}%
  else
    picknext#1!and #2!relax%
    if Fflipflop%
      edefsortedlist{sortedlist#1and }%
      defnext{sortlist#2and #3relax}%
    else%
      lettmpsortedlist%
      defsortedlist{}%
      defnext{expandaftersortlisttmp#2and #1and #3relax}%
    fi%
  fi%
next
}
defpicknext#1#2and #3#4relax{%
  ifnumthelccode`#1<thelccode`#3relax
    xdefflipflop{F}%
  else%
    ifnumthelccode`#1>thelccode`#3relax%
      xdefflipflop{T}%
    else%
      ZZfifi{picknext#2!and #4!relax}%
    fi%
  fi%
}
defZZfifi#1fifi{fifi#1}
defrework#1, #2and #3relax{#2#1ifxrelax#3relaxelse
  whichsep#3,relaxrework#3relaxfi}
defwhichsep#1,#2,#3relax{ifxrelax#3relax and else, fi}
begin{document}
defmydata{%
Gauss, Carl Friedrich and Riemann, Bernhard and Euler, Leonhard}
alphabubblesort{mydata}

I wish to thank 
alphabubblesort{%
Gauss, Carl Friedrich and 
Riemann, Bernhard and 
Euler, Leonhard and 
Bach, Carl Philipp Emanuel and 
Dumbledore, Albus Percival Wulfric Brian and 
Granger, Hermione Jean and 
Scott Thomas, Kristin and 
Van Gogh, Vincent and 
Sartre, Jean-Paul and 
Toulouse-Lautrec, Henri de}
for their valuable comments and incisive critiques.
end{document}

enter image description here

Answered by Steven B. Segletes on October 18, 2020

Here's a LuaLaTeX based solution. It sets up a LaTeX macro called sorted, which calls a Lua function called sorted to do most of the work. The word and is taken to be the keyword that separates persons, while , (comma) is the separator between the surname and given-name portions of a full name. Space characters and hyphen characters are allowed in both the given-name and first-name portions of a full name.

enter image description here

% !TeX program = lualatex
documentclass{article}

%% Lua-side code
usepackage{luacode} % for 'luacode' environment
begin{luacode}
function string_to_table ( str )
   local namelist = {} -- initialize the table
   str:gsub ( "([^;]*)" , function ( name ) 
        -- Strip off any leading and trailing whitespace:
        name = name:gsub ( "^%s*(.-)%s*$" , "%1" )
        -- Insert 'name' in 'namelist'
        table.insert ( namelist , name )   
        end )
   return namelist
end

function sorted ( s )
   local t
   -- Change the separator keyword "and" to ";"
   s = s:gsub ( "and" , ";" )
   -- Convert to a Lua table:
   t = string_to_table ( s )
   -- Sort the table entries alphabetically:
   table.sort ( t )
   n = #t -- Retrieve number of entries
   -- Change "Surname, FirstName" to "FirstName Surname":
   for i=1,n do
     t[i] = string.gsub ( t[i] , "([%a%s%-]+)%,%s?(.+)" , "%2 %1" )
   end
   -- Output a string, using "and" as the final separator
   s = t[1]
   for i = 2,n-1 do s = s .. ", " .. t[i] end
   s = s .. " and " .. t[n]
   tex.sprint ( s )
end

end{luacode}
%% LaTeX-side code:
newcommandsorted[1]{directlua{sorted(luastringN{#1})}}

begin{document}
I wish to thank 
sorted{Gauss, Carl Friedrich and Riemann,Bernhard and Euler, Leonhard and 
Bach, Carl Philipp Emanuel and Dumbledore,Albus Percival Wulfric Brian and 
Granger, Hermione Jean and Scott Thomas, Kristin and Van Gogh, Vincent and 
Sartre, Jean-Paul and Toulouse-Lautrec, Henri de}
for their valuable comments and incisive critiques.
end{document}

Answered by Mico on October 18, 2020

Add your own answers!

Ask a Question

Get help from others!

© 2024 TransWikia.com. All rights reserved. Sites we Love: PCI Database, UKBizDB, Menu Kuliner, Sharing RPP