1

Edit:

My objective is to sort a group of output strings, which are specified through names/codes.

  • There are effectively 3 components, the 'memorable codes' (names like Xenia, Alex, etc), the 'sorting key' (numbers like 1, 2, etc), and the 'anonymized code' (Interview1, Interview2, etc). My example (below) conflates the sorting key and anonymized code and tries to sort on the anonymized code.
  • The anonymized code and the sorting key are both subject to change between different drafts of the paper. Hence, they should be defined in one place and not be directly used anywhere in the text.
  • The memorable code is what the authors will use in the body text when they want the anonymized code to be written in the output. Wherever the anonymized codes are to be output, they should be output in order, sorted by their sorting key.

I'm using Steven's second solution. The output I was seeking is captured with:

Sorted anonymous (input by interviewees): \sortinterviewees{John, Julia, Xenia, Lucy}\par

Original (was titled: Sorting macros containing alphanumeric subscript)

I'm trying to produce sorted output and am using the revised sort by David posted here. I would like to know how this can be adapted to work with mixed alpha-numeric text containing subscript characters.

Minimal example:

\documentclass{article}
\usepackage{xspace}

%%% -- Copied sort -- %%%
\newcommand\alphabubblesort[1]{\def\sortedlist{}\expandafter\sortlist#1,\cr,\relax}
\def\sortlist#1,#2,#3\relax{%
  \let\next\relax
  \ifx\cr#2\relax%
    \edef\sortedlist{\sortedlist#1}%
  \else
    \picknext#1!,#2!\relax%
    \if F\flipflop%
      \edef\sortedlist{\sortedlist#1,}%
      \def\next{\sortlist#2,#3\relax}%
    \else%
      \let\tmp\sortedlist%
      \def\sortedlist{}%
      \def\next{\expandafter\sortlist\tmp#2,#1,#3\relax}%
    \fi%
  \fi%
\next
}
\def\picknext#1#2,#3#4\relax{%
  \ifnum\the\lccode`#1<\the\lccode`#3\relax
    \xdef\flipflop{F}%
  \else%
    \ifnum\the\lccode`#1>\the\lccode`#3\relax%
      \xdef\flipflop{T}%
    \else%
      \ZZfifi{\picknext#2!,#4!\relax}%
    \fi%
  \fi%
}
%%% ----------------- %%%


\newcommand\interview[1]{Interview$_{#1}$\xspace} 
%% Edit: added in some additional interviews.
\newcommand\Julia{\interview{1}}
\newcommand\Lucy{\interview{2}}
\newcommand\Alex{\interview{3}} 
\newcommand\Xenia{\interview{4}}
\newcommand\John{\interview{5}}
\newcommand\Jane{\interview{6}}


\begin{document}
How it should look:
\Julia, \Alex, \Xenia. 

But I'd like to be able to type:
\Alex, \Julia, \Xenia

This sort works on words only:
 \alphabubblesort{Alex, Xenia, Julia}\sortedlist
\end{document}

Example output:

output

In this example, please assume that it's also possible that in the future both the formatting and the numbering will change (which is of course why the dynamic numbering is desired in the first place), e.g., one possible variation is:

\newcommand\interview[1]{\textit{I$_{#1}$\xspace}} 
\newcommand\Julia{\interview{3}}
\newcommand\Alex{\interview{2}} 
\newcommand\Xenia{\interview{1}}
1

You can't sort on something that expands to formatting commands like \textit and \xspace. Instead, you will have to make a system whereby you sort on an alphabetic or numeric key and use the key to produce the formatted output.

REVISED APPROACH

I think the OP has finally agreed that the sort key can be numeric. In that case, the sorter need not be alphabetic, but can be a simple numerical bubble sort, as shown in this answer: Using LaTeX to compact a list of numbers

\documentclass{article}
\usepackage{listofitems}
\def\listterminator{-1}% SET TO *ANY* VALUE KNOWN NOT TO BE IN LIST (POSITIVE OR NEGATIVE)
\newcommand\bubblesort[1]{\def\sortedlist{}\sortlist#1,\listterminator,\relax}
\def\sortlist#1,#2,#3\relax{%
  \ifnum#2=\listterminator\relax%
    \edef\sortedlist{\sortedlist#1}%
  \else
    \ifnum#1<#2\relax%
      \edef\sortedlist{\sortedlist#1,}%
      \sortlist#2,#3\relax%
    \else%
      \let\tmp\sortedlist%
      \def\sortedlist{}%
      \expandafter\sortlist\tmp#2,#1,#3\relax%
    \fi%
  \fi%
}
\newcommand\interviewlist[2][a]{%
  \setsepchar{,}%
  \readlist*\mykeys{#2}%
  \foreachitem\x\in\mykeys[]{\ifnum\xcnt=1\else, \fi\interview{\x}%
  \ifx a#1\relax\else\ (\csname interview\x\endcsname)\fi}%
}
\newcommand\interview[1]{\textit{Interview$_{#1}$}} 
\newcommand\setinterview[2]{\expandafter\def\csname interview#1\endcsname{#2}}
\newcommand\sortinterviews[2][a]{\bubblesort{#2}\interviewlist[#1]{\sortedlist}}
\begin{document}
\setinterview{1}{Julia}
\setinterview{2}{Lucy}
\setinterview{3}{Alex}
\setinterview{4}{Xenia}
\setinterview{5}{John}
\setinterview{6}{Jane}
Bubble Sort Demonstration: \bubblesort{3,2,5}\sortedlist\par
Sorted anonymous: \sortinterviews{3 , 2 ,5}\par
Sorted revealed: \sortinterviews[]{3 , 2 ,5}
\end{document}

enter image description here

But here is a more sophisticated version that allows the interviews to be specified either by number (as shown in above MWE) or alternately by name. The approach here is to convert the name into an interview number before doing the sort, so that a numeric bubble-sort approach can be maintained.

There are several points of note. When the interviews are specified as

\setinterview{1}{Julia}
\setinterview{2}{Lucy}
\setinterview{3}{Alex}
\setinterview{4}{Xenia}
\setinterview{5}{John}
\setinterview{6}{Jane}

There are corresponding macros set for each one, such that \csname interview1\endcsname is set to {Julia} and \intervieweeJulia is set to {1}. This will allow one to extract numbers from names as well as vice-versa.

\documentclass{article}
\usepackage{listofitems}
\def\listterminator{-1}% SET TO *ANY* VALUE KNOWN NOT TO BE IN LIST (POSITIVE OR NEGATIVE)
\newcommand\bubblesort[1]{\def\sortedlist{}\sortlist#1,\listterminator,\relax}
\def\sortlist#1,#2,#3\relax{%
  \ifnum#2=\listterminator\relax%
    \edef\sortedlist{\sortedlist#1}%
  \else
    \ifnum#1<#2\relax%
      \edef\sortedlist{\sortedlist#1,}%
      \sortlist#2,#3\relax%
    \else%
      \let\tmp\sortedlist%
      \def\sortedlist{}%
      \expandafter\sortlist\tmp#2,#1,#3\relax%
    \fi%
  \fi%
}
\newcommand\interviewlist[2][a]{%
  \setsepchar{,}%
  \readlist*\mykeys{#2}%
  \foreachitem\x\in\mykeys[]{\ifnum\xcnt=1\else, \fi\interview{\x}%
  \ifx a#1\relax\else\ (\csname interview\x\endcsname)\fi}%
}
\newcommand\interview[1]{\textit{Interview$_{#1}$}} 
\newcommand\setinterview[2]{%
  \expandafter\def\csname interview#1\endcsname{#2}%
  \expandafter\def\csname interviewee#2\endcsname{#1}%
}
\newcommand\sortinterviews[2][a]{\bubblesort{#2}\interviewlist[#1]{\sortedlist}}
\newcommand\sortinterviewees[2][a]{%
  \setsepchar{,}%
  \readlist*\mynames{#2}%
  \def\tmp{}%
  \foreachitem\x\in\mynames[]{%
    \ifnum\xcnt=1\relax\else\edef\tmp{\tmp,}\fi%
    \edef\tmp{\tmp\csname interviewee\x\endcsname}%
  }%
  \expandafter\bubblesort\expandafter{\tmp}\interviewlist[#1]{\sortedlist}%
}
\begin{document}
\setinterview{1}{Julia}
\setinterview{2}{Lucy}
\setinterview{3}{Alex}
\setinterview{4}{Xenia}
\setinterview{5}{John}
\setinterview{6}{Jane}
Input by interview numbers: 3, 2, 5\par
Sorted anonymous: \sortinterviews{3 , 2 ,5}\par
Sorted revealed: \sortinterviews[]{3 , 2 ,5}\par\medskip
Input by interviewees: John, Julia, Xenia\par
Sorted anonymous: \sortinterviewees{John, Julia, Xenia}\par
Sorted revealed: \sortinterviewees[]{John, Julia, Xenia}\par
\end{document}

enter image description here

|improve this answer|||||
  • If I understand you correctly, the answer is that it is not possible in LaTeX. In the original context, human-readable names would not be output nor used for sorting, only as an alias for the author. It is the anonymized codes (in this example numbers) which are sorted on. At the points where the author wants to reference them, s/he knows by name which people were interviewed, but has no recollection of what code each might currently be anonymized under. In such a situation the only solution would be to sort manually, redoing it each time the coding system changes? – Ann Mar 27 '19 at 13:00
  • @Ann You need a key-list which will be sorted, and you can get output based on the sorted key list. But perhaps I have misunderstood the question. I assumed the key list on which to sort was the names of the interviewees. If you wanted the keys to be the interview number, for example, so that you sort by 1st interview, 2nd interview, etc., then you would create a macro something to the effect of \expandafter\def\csname interview1\endcsname{Jenia}, etc. – Steven B. Segletes Mar 27 '19 at 13:05
  • @Ann My confusion arises because you say how it should look is "Interview1, Interview2, Interview3". But that sort doesn't require any names whatsoever. So where do the actual names come in? – Steven B. Segletes Mar 27 '19 at 13:07
  • 1
    @Ann Please see my revision. If the sort key is numeric, a simpler sort algorithm may be employed. – Steven B. Segletes Mar 27 '19 at 14:25
  • 1
    The second solution in the revised answer is exactly what I was looking for! Thank you for your perseverance. (I'll add some of our discussion to the original post to clarify for anyone looking at the post later.) – Ann Mar 27 '19 at 15:40

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.