Emparelhar itens de duas listas separadas por vírgula em uma única lista

Emparelhar itens de duas listas separadas por vírgula em uma única lista

Como emparelhar itens de duas listas separadas por vírgula (supondo que tenham o mesmo comprimento) em outra lista?

Fiz o meu melhor procurando a resposta antes de perguntar… então espero que não seja uma duplicata!

Por exemplo, dado a listas \def\a{1,2,3,4,5} e \def\b{a,b,c,d,e} quero definir \parlistso que \def\c{\pairlists[=]{\a}{\b}} irá definir \c as {1=a,2=b,3=c,4=d,5=e}.

Não sou nenhum especialista em TeX, mas, ainda assim, tive sucesso parcial: funciona quando as listas são fornecidas como parâmetros, mas não quando as listas são armazenadas nos comandos \ae \b. Veja minha tentativa abaixo… Qualquer ajuda será muito apreciada. Obrigado.

\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}

insira a descrição da imagem aqui

Responder1

Esta é uma solução usando a abordagem LaTeX3. Vale a pena notar que o LaTeX é uma linguagem macro. Você pode usar \meaningpara mostrar a definição de um comando. Quando você define \def\x{\pairitems{\a}{\b}}, então \xé \pairitems{\a}{\b}, literalmente, o valor de \pairitems{\a}{\b}. Se você deseja \xconter o valor de \pairitems{\a}{\b}, algum tratamento especial precisa ser feito.

\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}

Responder2

Isso produz saída terminal

> \zc=macro:
->1=a, 2=b, 3=c, 4=d, 5=e.

e digitado

insira a descrição da imagem aqui

Observe o uso de \unexpandedpara que os termos da lista sejam protegidos contra expansão, mesmo que edef seja usado para salvar o resultado. Alterei a ordem de chamada fazendo o comando definir o 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}

Responder3

Você precisa fazer alguns \expandaftertruques de troca de argumentos para que as macros que contêm as listas de itens separados por vírgula sejam expandidas antes de \pairitemsserem executadas.

Caso você não goste de usar \edef(o que também acionaria a expansão dos itens separados por vírgula da lista de vírgulas), você pode (ab?) usar \romannumeralo que aciona a expansão até reunir um TeX válido.⟨número⟩-quantidade e caso TeX-⟨número⟩-quantidade denota um valor não positivo silenciosamente apenas engole os tokens formando aquele TeX-⟨número⟩-quantidade.

\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}

insira a descrição da imagem aqui

É claro que tudo isso não leva em conta o caso de duas listas vazias.
Além disso, não há tratamento de tokens de espaço em torno de itens de lista separados por vírgula.
Além disso, não há tratamento especial para itens de lista em branco/vazio.

Responder4

Tornei a sintaxe um pouco diferente, se funcionar para o OP. Aqui, executa-se \makepairlist[=]{\a}{\b}para criar a lista de pares desejada em uma macro \thepairlist. No MWE, mostro que a macro destokenizada já está expandida para a lista desejada.

Se desejar, pode-se acompanhar \edef\c{\thepairlist}ou, melhor ainda, \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}

insira a descrição da imagem aqui

informação relacionada