Объединение элементов из двух списков, разделенных запятыми, в один список

Объединение элементов из двух списков, разделенных запятыми, в один список

Как объединить элементы из двух списков, разделенных запятыми (при условии, что они имеют одинаковую длину), в другой список?

Я приложил все усилия, чтобы найти ответ, прежде чем задать вопрос... поэтому надеюсь, что это не дубликат!

Например, даны списки, \def\a{1,2,3,4,5} и \def\b{a,b,c,d,e} я хочу определить \parlistsтакие, которые \def\c{\pairlists[=]{\a}{\b}} будут определять \c as {1=a,2=b,3=c,4=d,5=e}.

Я совсем не эксперт по TeX, но, тем не менее, мне удалось добиться частичного успеха: это работает, когда списки указаны как параметры, но не когда списки хранятся в командах \aи \b. См. мою попытку ниже... Любая помощь будет высоко оценена. Спасибо.

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

введите описание изображения здесь

решение1

Это решение с использованием подхода LaTeX3. Стоит отметить, что LaTeX — это макроязык. Вы можете использовать , \meaningчтобы показать определение команды. Когда вы определяете \def\x{\pairitems{\a}{\b}}, то \xэто \pairitems{\a}{\b}, буквально, вместо значения \pairitems{\a}{\b}. Если вы хотите \xвключить значение \pairitems{\a}{\b}, необходимо выполнить некоторую специальную обработку.

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

решение2

Это создает терминальный вывод

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

и набранный

введите описание изображения здесь

Обратите внимание на использование \unexpanded, чтобы термины в списке были защищены от расширения, даже если edef используется для сохранения результата. Я изменил порядок вызова, заставив команду определить указанный токен\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}

решение3

Вам нужно проделать некоторые \expandafterтрюки с обменом аргументами, чтобы макросы, содержащие списки элементов, разделенных запятыми, были расширены перед \pairitemsвыполнением.

В случае, если вы не хотите использовать \edef(что также вызовет расширение самих элементов списка, разделенных запятыми), вы можете (ab?)использовать, \romannumeralчто вызовет расширение, пока не соберете допустимый TeX-⟨число⟩-количество и в случае, если TeX-⟨число⟩-количество обозначает неположительное значение, молча просто поглощает токены, образуя этот TeX-⟨число⟩-количество.

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

введите описание изображения здесь

Конечно, все это не принимает во внимание случай двух пустых списков.
Также нет обработки пробельных токенов, окружающих разделенные запятыми элементы списка.
Также нет специальной обработки пустых/пустых элементов списка.

решение4

Я сделал синтаксис немного другим, если это работает для OP. Здесь выполняется \makepairlist[=]{\a}{\b}для создания нужного списка пар в макросе \thepairlist. В MWE я показываю, что детокенизированный макрос уже расширен до нужного списка.

При желании можно было бы продолжить с помощью \edef\c{\thepairlist}или, что еще лучше, \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}

введите описание изображения здесь

Связанный контент