
¿Cómo emparejar elementos de dos listas separadas por comas (suponiendo que tengan la misma longitud) en otra lista?
Hice lo mejor que pude para buscar la respuesta antes de preguntar... ¡así que espero que esto no sea un duplicado!
Por ejemplo, dado a las listas
\def\a{1,2,3,4,5}
y
\def\b{a,b,c,d,e}
quiero definir \parlists
las que
\def\c{\pairlists[=]{\a}{\b}}
definirán
\c as {1=a,2=b,3=c,4=d,5=e}
.
No soy ningún experto en TeX, pero aun así tuve un éxito parcial: funciona cuando las listas se dan como parámetros, pero no cuando las listas se almacenan en los comandos \a
y \b
. Vea mi intento a continuación... Cualquier ayuda será muy apreciada. Gracias.
\documentclass{minimal}
\usepackage{xifthen}
\makeatletter
\def\@pairitems[#1]#2,#3\@nil#4,#5\@nil{%
% [#1][#2,#3][#4,#5]%
\ifthenelse{\equal{#3}{}}{%
\ifthenelse{\equal{#5}{}}%
{#2#1#4}%
{\PackageError{example}{Lists are not the same size}}%
}{%
\ifthenelse{\equal{#5}{}}%
{\PackageError{example}{Lists are not the same size}}%
{#2#1#4, \@pairitems[#1]#3\@nil#5\@nil}%
}%
}
\def\pairitems[#1]#2#3{\@pairitems[#1]#2,\@nil#3,\@nil}
\makeatother
\begin{document}
\def\a{1,2,3,4,5}
\def\b{a,b,c,d,e}
\def\x{\pairitems[=]{1,2,3,4,5}{a,b,c,d,e}}
\def\y{\pairitems[=]{\a}{\b}}
\noindent
x: \x\\
y: \y\\
\end{document}
Respuesta1
Esta es una solución que utiliza el enfoque LaTeX3. Vale la pena señalar que LaTeX es un lenguaje de macros. Puede utilizar \meaning
para mostrar la definición de un comando. Cuando defines \def\x{\pairitems{\a}{\b}}
, entonces \x
es \pairitems{\a}{\b}
, literalmente, el valor de \pairitems{\a}{\b}
. Si desea \x
contener el valor de \pairitems{\a}{\b}
, es necesario realizar algún tratamiento especial.
\documentclass{minimal}
\usepackage[T1]{fontenc}
\usepackage{expl3}
\usepackage{xparse}
\ExplSyntaxOn
\clist_new:N \l_doc_tmpa_clist
\clist_new:N \l_doc_tmpb_clist
\seq_new:N \l_doc_tmpa_seq
\msg_new:nnn {doc} {difflen} {two~comma~separated~lists~have~different~length}
\cs_set:Npn \doc_pair_items:nnn #1#2#3 {
\clist_set:Nn \l_doc_tmpa_clist {#2}
\clist_set:Nn \l_doc_tmpb_clist {#3}
\seq_clear:N \l_doc_tmpa_seq
\int_compare:nNnF {\clist_count:N \l_doc_tmpa_clist} = {\clist_count:N \l_doc_tmpb_clist} {
\msg_error:nn {doc} {difflen}
}
\int_step_inline:nn {\clist_count:N \l_doc_tmpa_clist} {
\seq_put_right:Nn \l_doc_tmpa_seq {
\clist_item:Nn \l_doc_tmpa_clist {##1}
#1
\clist_item:Nn \l_doc_tmpa_clist {##1}
}
}
\seq_use:Nn \l_doc_tmpa_seq {,}
}
\cs_generate_variant:Nn \doc_pair_items:nnn {nxx}
\cs_generate_variant:Nn \doc_pair_items:nnn {noo}
\newcommand{\pairitems}[3][=]{
\doc_pair_items:nnn {#1} {#2} {#3}
}
\newcommand{\pairitemso}[3][=]{
\doc_pair_items:noo {#1} {#2} {#3}
}
\newcommand{\pairitemsx}[3][=]{
\doc_pair_items:nxx {#1} {#2} {#3}
}
\ExplSyntaxOff
\begin{document}
\par\pairitems{1,2,3,4,5}{a,b,c,d,e}
\par\pairitems[+]{1,2,3,4,5}{a,b,c,d,e}
\def\a{1,2,3,4,5}
\def\b{a,b,c,d,e}
\par\pairitems{\a}{\b}
\par\pairitemso{\a}{\b}
\def\x{\pairitemso{\a}{\b}}
\par\meaning\x
\edef\x{\noexpand\pairitemso{\a}{\b}}
\par\meaning\x
\end{document}
Respuesta2
Esto produce una salida terminal.
> \zc=macro:
->1=a, 2=b, 3=c, 4=d, 5=e.
y componer
Tenga en cuenta el uso de \unexpanded
para que los términos de la lista estén protegidos contra la expansión, aunque se utilice edef para guardar el resultado. Cambié el orden de llamada haciendo que el comando defina el token especificado\zc
\documentclass{article}
% don't break latex accent support by redefining \a \b or \c which are
% all core latex commands....
\def\za{1,2,3,4,5}
\def\zb{a,b,c,d,e}
\newcommand\pairlists[4][=]{%
\edef#2{%
\expandafter\expandafter\expandafter\xpairlists
\expandafter#3\expandafter,\expandafter\relax#4,\relax#1\zstop
}}
\def\xpairlists#1,#2\relax#3,#4\relax#5\zstop{%
\unexpanded{#1#5#3}%
\ifcat$\detokenize{#2}$%
\expandafter\gobblezstop
\fi
, \xpairlists#2\relax#4\relax#5\zstop}
\def\gobblezstop#1\zstop{}
\pairlists[=]{\zc}{\za}{\zb}
\show\zc
\begin{document}
\zc
\end{document}
Respuesta3
Necesita hacer algunos \expandafter
trucos de intercambio de argumentos para que las macros que contienen las listas de elementos separados por comas se expandan antes de \pairitems
llevarse a cabo.
En caso de que no le guste usar \edef
(lo que también desencadenaría la expansión de los elementos separados por comas de la lista de comas), puede (¿ab?)usar \romannumeral
lo que desencadena la expansión hasta que haya reunido un archivo TeX válido.⟨número⟩-cantidad y en caso de que TeX-⟨número⟩-cantidad denota un valor no positivo, simplemente devora silenciosamente los tokens que forman ese TeX-⟨número⟩-cantidad.
\documentclass[a4paper, landscape]{article}
%===================[adjust margins/layout for the example]====================
\csname @ifundefined\endcsname{pagewidth}{}{\pagewidth=\paperwidth}%
\csname @ifundefined\endcsname{pdfpagewidth}{}{\pdfpagewidth=\paperwidth}%
\csname @ifundefined\endcsname{pageheight}{}{\pageheight=\paperheight}%
\csname @ifundefined\endcsname{pdfpageheight}{}{\pdfpageheight=\paperheight}%
\textwidth=\paperwidth
\oddsidemargin=1.5cm
\marginparsep=.2\oddsidemargin
\marginparwidth=\oddsidemargin
\advance\marginparwidth-2\marginparsep
\advance\textwidth-2\oddsidemargin
\advance\oddsidemargin-1in
\evensidemargin=\oddsidemargin
\textheight=\paperheight
\topmargin=1.5cm
\footskip=.5\topmargin
{\normalfont\global\advance\footskip.5\ht\strutbox}%
\advance\textheight-2\topmargin
\advance\topmargin-1in
\headheight=0ex
\headsep=0ex
\pagestyle{plain}
\parindent=0ex
\parskip=0ex
\topsep=0ex
\partopsep=0ex
%==================[eof margin-adjustments]====================================
\makeatletter
\newcommand\Exchange[2]{#2#1}%
\newcommand\CheckWhetherNull[1]{%
\ifcat Y\detokenize{#1}Y%
\expandafter\@firstoftwo\else\expandafter\@secondoftwo\fi
}%
\@ifdefinable\@pairitems{%
\long\def\@pairitems#1#2,#3\@nil#4,#5\@nil#6{%
\CheckWhetherNull{#3}{%
\CheckWhetherNull{#5}%
{\z@#6#2#1#4}%
{\z@\PackageError{example}{Lists are not the same size}}%
}{%
\CheckWhetherNull{#5}%
{\z@\PackageError{example}{Lists are not the same size}}%
{\@pairitems{#1}#3\@nil#5\@nil{#6#2#1#4,}}%
}%
}%
}%
\newcommand\pairitems[3]{\romannumeral\@pairitems{#1}#2,\@nil#3,\@nil{}}
\makeatother
\begin{document}
\newcommand*\one{1}
\newcommand*\two{2}
\newcommand*\three{3}
\newcommand*\four{4}
\newcommand*\five{5}
\newcommand*\MYa{a}
\newcommand*\MYb{b}
\newcommand*\MYc{c}
\newcommand*\MYd{d}
\newcommand*\MYe{e}
\newcommand*\ListA{\one,\two,\three,\four,\five}
\newcommand*\ListB{\MYa,\MYb,\MYc,\MYd,\MYe}
\newcommand*\PairedU{\pairitems{=}{\one,\two,\three,\four,\five}{\MYa,\MYb,\MYc,\MYd,\MYe}}
\newcommand*\PairedV{\expandafter\Exchange\expandafter{\expandafter{\ListB}}{\expandafter\Exchange\expandafter{\expandafter{\ListA}}{\pairitems{=}}}}
\expandafter\newcommand\expandafter*\expandafter\PairedW\expandafter{%
\romannumeral0\Exchange{ }{\expandafter\expandafter\expandafter}\pairitems{=}{\one,\two,\three,\four,\five}{\MYa,\MYb,\MYc,\MYd,\MYe}%
}
\expandafter\newcommand\expandafter*\expandafter\PairedX\expandafter{%
\romannumeral0%
\expandafter\Exchange\expandafter{\expandafter{\ListB}}{%
\expandafter\Exchange\expandafter{\expandafter{\ListA}}{%
\Exchange{ }{\expandafter\expandafter\expandafter}\pairitems{=}%
}%
}%
}
\csname @ifdefinable\endcsname\PairedY{%
\edef\PairedY{\pairitems{=}{\one,\two,\three,\four,\five}{\MYa,\MYb,\MYc,\MYd,\MYe}}%
}%
\csname @ifdefinable\endcsname\PairedZ{%
\edef\PairedZ{\expandafter\Exchange\expandafter{\expandafter{\ListB}}{\expandafter\Exchange\expandafter{\expandafter{\ListA}}{\pairitems{=}}}}%
}%
\noindent{\ttfamily \string\PairedU:\\\meaning\PairedU}\\$\to$\PairedU\bigskip
\noindent{\ttfamily \string\PairedV:\\\meaning\PairedV}\\$\to$\PairedV\bigskip
\noindent{\ttfamily \string\PairedW:\\\meaning\PairedW}\\$\to$\PairedW\bigskip
\noindent{\ttfamily \string\PairedX:\\\meaning\PairedX}\\$\to$\PairedX\bigskip
\noindent{\ttfamily \string\PairedY:\\\meaning\PairedY}\\$\to$\PairedY\bigskip
\noindent{\ttfamily \string\PairedZ:\\\meaning\PairedZ}\\$\to$\PairedZ
\end{document}
Por supuesto, todo esto sin tener en cuenta el caso de dos listas vacías.
Además, no se tratan los tokens de espacio que rodean los elementos de la lista separados por comas.
Además, no existe un tratamiento especial para los elementos de la lista en blanco o vacía.
Respuesta4
Hice la sintaxis un poco diferente, si eso funciona para el OP. Aquí, se ejecuta \makepairlist[=]{\a}{\b}
para crear la lista de pares deseada en una macro \thepairlist
. En el MWE, muestro que la macro detokenizada ya está expandida a la lista deseada.
Si se desea, se puede continuar con \edef\c{\thepairlist}
o, mejor aún, \let\c\thepairlist
.
\documentclass{article}
\usepackage{listofitems}
\newcommand\makepairlist[3][:]{%
\readlist\ListA{#2}%
\readlist\ListB{#3}%
\def\thepairlist{}%
\foreachitem\z\in\ListA[]{%
\ifnum\zcnt=1\relax\else\edef\thepairlist{\thepairlist,}\fi
\edef\thepairlist{\thepairlist\z#1\ListB[\zcnt]}%
}%
}
\begin{document}
\def\a{1,2,3,4,5}
\def\b{a,b,c,d,e}
\makepairlist[=]{\a}{\b}
\thepairlist
\detokenize\expandafter{\thepairlist}
\end{document}