Great to see expl3
in use in egreg's answer. Given the recent developments in the LaTeX3 interfaces I would like to "slightly" improve or change it as follows:
\documentclass{article}
\usepackage{xparse}
\ExplSyntaxOn
% package level definitions
\seq_new:N \l__morbusg_left_seq
\seq_new:N \l__morbusg_right_seq
% public package interface command
\cs_new:Npn \morbusg_zip:Nnnnn #1 #2 #3 #4 #5 {
\seq_set_split:Nnn \l__morbusg_left_seq { #2 } { #3 }
\seq_set_split:Nnn \l__morbusg_right_seq { #4 } { #5 }
\seq_mapthread_function:NNN \l__morbusg_left_seq \l__morbusg_right_seq #1
}
% xparse interface
\NewDocumentCommand{\zip}{ m O{,} m o m }
{ \IfNoValueTF {#4}
{ \morbusg_zip:Nnnnn #1 {#2} {#3} {#2} {#5} }
{ \morbusg_zip:Nnnnn #1 {#2} {#3} {#4} {#5} }
}
\ExplSyntaxOff
\newcommand{\foo}[2]{First is #1, second is #2\par}
\newcommand{\baz}[2]{Left is #1, right is #2\par}
\begin{document}
\zip{\foo}{a,b,c}{d,e,f}
\zip{\baz}[;]{A;B;C}{D;E;F}
\zip{\baz}{1,2,3}[!!]{X!!Y!Y!!Z}
\zip{\foo}[&]{9&8&7}[$]{5$4$3}
\end{document}
So what is different?
Clear separation of functional interface \morbusg_zip:Nnnnn
and document level interface \zip
.
As I outlined in What can *I* do to help the LaTeX3 Project the architecture of LaTeX3 separates out the two very clearly. xparse
is a document level syntax package that implements LaTeX2e like syntax with optional arguments etc. But there might, and probably will, be alternatives, e.g., a key/value type of document level syntax, or an xml like syntax.
If properly separated the functional code, i.e., \morbusg_zip:Nnnnn
would remain unchanged and you only switch the document level parsing routines. Maybe feels a bit like overkill in this particular example, but it helps to think in this way throughout and use the separation as best practice.
Support for different separators on the two lists.
The original solution used one and the same operator. I extended the functional definition to use one separator per list. So the functional definition offers more possibilities and it is up to the user interface to use or not use them, e.g., to get egreg's interface the definition for \zip
would have been
\NewDocumentCommand{\zip}{ m O{,} m m }
{ \morbusg_zip:Nnnnn #1 {#2} {#3} {#2} {#4} }
i.e., reusing the same separator for both lists. Again that shows (imnsho) the advantage of decoupling the two levels.
Clearly separating public interface and internal commands and variables
Well, this time we only have one function and it is public, so only the two variables got marked as internal (which is they use __
in their name). In a package one would/could have shortened that to \l_@@_left_seq
where @@
is a shorthand for the current "module" name with two __
in front.
If the extended version is run through TeX you will get the following output (as you can see, stranger separators are possible too, e.g., !!
, or $
but that was already in the original solution):