
如何將兩個逗號分隔清單中的項目(假設它們具有相同的長度)配對到另一個清單中?
在提問之前我盡了最大努力尋找答案......所以我確實希望這不是重複的!
例如,給定列表
\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}}
,then從字面上\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-⟨數字⟩-quantity 表示一個非正值,默默地吞噬形成 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}