3

Is there a way to write a macro that steps through two lists of arguments pairwise, like what Python's zip function does? For example, I'd like to write a macro like this (using xparse because that's what I've been experimenting with; I'm open to other options):

\NewDocumentCommand{\Zip}{ >{\SplitList{,}}m >{\SplitList{,}}m }{%
    % something that calls \myfunc in an itemize environment
}

\newcommand{\myfunc}[2]{\item #1, #2}

So that calling Zip{zebra,frog,jay}{mammal,amphibian,bird} is equivalent to

\begin{itemize}
    \item zebra, mammal
    \item frog, amphibian
    \item jay, bird
\end{itemize}

Is this possible? I've looked into xparse but it seems to only allow stepping through two lists one at a time, not zipping them together. There was a similar question here back in 2011, but I hope there's a nicer solution now.

1

2 Answers 2

3

You can use \seq_mapthread_function:NNN to iterate over two seq variables like that.

enter image description here

\documentclass{article}

\ExplSyntaxOn
\seq_new:N \l__gil_tmpa_seq
\seq_new:N \l__gil_tmpb_seq
\NewDocumentCommand \Zip { m m }
  {
    \seq_set_from_clist:Nn \l__gil_tmpa_seq {#1}
    \seq_set_from_clist:Nn \l__gil_tmpb_seq {#2}
    \seq_mapthread_function:NNN
      \l__gil_tmpa_seq \l__gil_tmpb_seq \myfunc
  }
\ExplSyntaxOff

\newcommand{\myfunc}[2]{\item #1, #2}

\begin{document}

\begin{itemize}
  \Zip{zebra,frog,jay}{mammal,amphibian,bird}
\end{itemize}

\end{document}
8
  • Nice, exactly what I need! I'll see if someone has a higher-level solution (I was kind of expecting there to be one) but if not, I will accept your answer.
    – gil
    Oct 27, 2020 at 18:05
  • @gil How higher-level do you mean? \seq_mapthread_function:NNN is a documented interface in expl3, so it is really not “low level”. If you mean something built into xparse, then the answer is no, it doesn't have that. Oct 27, 2020 at 18:14
  • I mean if some package offers an easy, xparse-like interface for zipping (which xparse doesn't do, I know), I'd prefer that. Maybe I was hoping for too much.
    – gil
    Oct 27, 2020 at 21:23
  • @gil It's rather specific, so I don't think so (but there are thousands of packages out there, so there might as well be, but none that I know of). There's \foreach from the pgffor package, which is quite powerful and maybe has something to do this (I know it can do a for loop with two counters, like C's for; I don't know about arbitrary lists). Oct 27, 2020 at 21:32
  • This is essentially identical to my answer to the question marked as duplicate, although not as powerful.
    – egreg
    Oct 28, 2020 at 18:20
0

Using \foreach from pgffor, to illustrate as per the comment.

Traverse the diagonal of the matrix of pairwise combinations:

\foreach \x [count=\xi] in {#1}{%
\foreach \y [count=\yi] in {#2}{%
\ifnum \xi=\yi%
\item \x , \y 
\fi
}
}

zipped pairs

MWE


\documentclass{article}
\usepackage{xparse}
\usepackage{pgffor}

\ExplSyntaxOn
\seq_new:N \l__gil_tmpa_seq
\seq_new:N \l__gil_tmpb_seq
\NewDocumentCommand \Zip { m m }
  {
    \seq_set_from_clist:Nn \l__gil_tmpa_seq {#1}
    \seq_set_from_clist:Nn \l__gil_tmpb_seq {#2}
    \seq_mapthread_function:NNN
      \l__gil_tmpa_seq \l__gil_tmpb_seq \myfunc
  }
\ExplSyntaxOff

\newcommand{\myfunc}[2]{\item #1, #2}

\newcommand{\myfuncb}[2]{%
\begin{itemize}
\foreach \x [count=\xi] in {#1}{%
\foreach \y [count=\yi] in {#2}{%
\ifnum \xi=\yi%
\item \x , \y 
\fi
}
}
\end{itemize}
}



\begin{document}

Expl3:
\begin{itemize}
  \Zip{zebra,frog,jay}{mammal,amphibian,bird}
\end{itemize}

\textbackslash foreach:
\myfuncb{zebra,frog,jay}{mammal,amphibian,bird}

\end{document}

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