1

I have a permutated list which I sort, which I then use as shades for some TikZ figures.

\documentclass{article}
\usepackage{expl3, tikz}

\ExplSyntaxOn
\clist_new:N \l_my_clist
\NewDocumentCommand{\sorted}{m}
{
  \clist_set:Nx \l_my_clist {#1}
  \clist_sort:Nn \l_my_clist
  { \int_compare:nTF { ##1 > ##2 } { \sort_return_swapped: } { \sort_return_same: } }
  \clist_use:Nn \l_my_clist
}
\ExplSyntaxOff
\newcommand{\myperm}{1,8,15,4,6,5,12,10,13,2,11,14,7,16,3,9}
\newcommand{\mysorted}{\sorted{\myperm}}
\begin{document}

\foreach \x [evaluate=\x as \shade using \x*6] in \myperm{
  \x~\shade\\
}\\

\foreach \x [evaluate=\x as \shade using \x*6] in \mysorted{
  \x~\shade
}

\end{document}

The evaluation of the second loop doesn't compile, with the error:

\LaTeX3 error: 
                A sequence was misused.

I suppose the elements of the sorted list are somehow not integers. How to expand them so?

1
  • \mysorted is not a comma separated list.
    – egreg
    Feb 1, 2021 at 11:39

1 Answer 1

1

Welcome to TeX.SE. There are essentially two problems in your code:

  1. Your \clist_use:Nn \l_my_clist call is missing the n-type argument, which should be the separator you want to be used between items. For instance, \clist_use:Nn \l_my_clist { , } can be used in order to separate items with a comma.

  2. In order for \foreach \x ... in \mysorted to work, \mysorted has to expand to a comma-separated list. However, your \mysorted macro expands to \sorted{\myperm} and your \sorted macro contains several commands that are not expandable (\clist_set:Nx and \clist_sort:Nn). Moreover, your \sorted macro is \protected because it is defined with \NewDocumentCommand, therefore it won't expand in expansion-only contexts, which is generally required for this kind of parsing. Therefore, the code can't work this way.

I propose a simple modification: rename your \mysorted macro to \mysort and give it two arguments. The second argument is interpreted as the only argument of your \sorted macro. The first argument is a control sequence token in which \mysort stores the result of the sorting operation. Thus, the first-level expansion of the specified control sequence token will be a comma-separated list after \mysort has completed its work.

(Also, since there is no risk here, we can use the already-defined \l_tmpa_clist variable instead of \l_my_clist—which should probably have been named \l__my_clist, by the way: private variable.)

\documentclass{article}
\usepackage{xparse}    % only necessary if LaTeX format older than 2020-10-01
\usepackage{pgffor}
\usepackage{multicol}  % for a nicer layout

\ExplSyntaxOn
\NewDocumentCommand \mysort { m m }
  {
    \clist_set:Nx \l_tmpa_clist {#2}
    \clist_sort:Nn \l_tmpa_clist
      {
        \int_compare:nTF { ##1 > ##2 }
          { \sort_return_swapped: }
          { \sort_return_same: }
      }

    \tl_set:Nx #1 { \clist_use:Nn \l_tmpa_clist { , } }
  }
\ExplSyntaxOff

\newcommand{\myperm}{1,8,15,4,6,5,12,10,13,2,11,14,7,16,3,9}
% The first argument specifies where to store the result.
\mysort{\mysorted}{\myperm}

\begin{document}

\begin{multicols}{2}
\foreach \x [evaluate=\x as \shade using \x*6] in \myperm {
  \x~\shade\par
}%
\columnbreak

\bigskip
\foreach \x [evaluate=\x as \shade using \x*6] in \mysorted {
  \x~\shade\par
}
\end{multicols}

\end{document}

enter image description here

As mentioned in the comments and shown below, one can also do this:

  • using a seq variable instead of a clist;
  • using \int_compare:nNnTF {##1} > {##2} instead of \int_compare:nTF { ##1 > ##2 } for the sorting operation (this should make the sorting faster).
\documentclass{article}
\usepackage{xparse}    % only necessary if LaTeX format older than 2020-10-01
\usepackage{pgffor}
\usepackage{multicol}  % for a nicer layout

\ExplSyntaxOn
\cs_generate_variant:Nn \seq_set_from_clist:Nn { Nx }

\NewDocumentCommand \mysort { m m }
  {
    \seq_set_from_clist:Nx \l_tmpa_seq {#2}
    \seq_sort:Nn \l_tmpa_seq
      {
        \int_compare:nNnTF {##1} > {##2}
          { \sort_return_swapped: }
          { \sort_return_same: }
      }

    \tl_set:Nx #1 { \seq_use:Nn \l_tmpa_seq { , } }
  }
\ExplSyntaxOff

\newcommand{\myperm}{1,8,15,4,6,5,12,10,13,2,11,14,7,16,3,9}
% The first argument specifies where to store the result.
\mysort{\mysorted}{\myperm}

\begin{document}

\begin{multicols}{2}
\foreach \x [evaluate=\x as \shade using \x*6] in \myperm {
  \x~\shade\par
}%
\columnbreak

\bigskip
\foreach \x [evaluate=\x as \shade using \x*6] in \mysorted {
  \x~\shade\par
}
\end{multicols}

\end{document}
4
  • Thanks! Is this sort of destination-passing-style commonplace in Latex3 programming? I never encountered it (but I must say I am fairly new to it) Feb 2, 2021 at 13:23
  • If this is what you mean, it is common in (La)TeX programming to do something using “non-expandable” operations (typically, assignments), store the result in a macro and then use this macro in a place where only expansion can take place. This is exactly what we are doing here. Many zref operations work this way, as well as \pgfmathmarse (non-expandable which stores the result in \pgfmathresult), etc. Many expl3 functions that “set” a “variable” to something take the corresponding control sequence token as their first arg (\tl_set:Nn, \seq_set_from_clist:NN and many others), ...
    – frougon
    Feb 2, 2021 at 17:43
  • ... which is why I used this convention. Note: you could probably make the code faster at no cost by using \int_compare:nNnTF {##1} > {##2} instead of \int_compare:nTF { ##1 > ##2 } (this could have a measurable impact with non-trivial amounts of data, since it is used as the inner operation for the sorting here). Also, using a seq instead of a clist might speed things up, though I'm not sure about this one.
    – frougon
    Feb 2, 2021 at 17:45
  • I've added a variant of the code with these little changes.
    – frougon
    Feb 2, 2021 at 18:01

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .