如何从任意参数序列生成矩阵?

如何从任意参数序列生成矩阵?

这个答案向我展示了如何处理任意数量的参数。我根据自己的目的对其进行了一点调整:

\usepackage{pgffor}
\newcommand*{\twolinematrix}[1]{%
    \foreach \firstrowelement/\secondrowelement in {#1} {%
        <something should happen here!}%
    } 
}

上述宏应以这样的输入为例:\autotwolinematrix{1/6, 2/7, 3/8, 4/9, 5/10}

我陷入了困境,因为通常情况下,如果你想创建一个矩阵(假设你已经amsmath加载),你会这样做:

\newcommand{\manualtwolinematrix}[10]{%
    \begin{matrix} 
        #1 & #2 & #3 & #4 & #5 \\
        #6 & #7 & #8 & #9 & #10
    \end{matrix}%
}

因此,这意味着您需要有逻辑来知道何时完成元素对,因为您必须放置\\。我认为如果我们以编程方式生成矩阵,最好这样想:

\newcommand{\manualtwolinematrix}[10]{%
    \begin{matrix} 
        #1 & #2 & #3 & #4 & #5 \\ #6 & #7 & #8 & #9 & #10
    \end{matrix}%
}

其中#1 & #2 & #3 & #4 & #5 \\ #6 & #7 & #8 & #9 & #10是宏主体中必须自动生成的字符串。我们的宏成对地获取输入,因此我们必须根据成对的输入生成此字符串。好的,那么在宏主体中,我们应该有两个变量:\firstrow\secondrow

给定每对元素,应该按顺序构建和,最后生成一个名为的变量,如下所示\firstrow\secondrow\matrixbody

\matrixbody = \firstrow \\ \secondrow

你能帮我整理一下这些想法吗?

答案1

也许不如手工制作的递归宏有吸引力,但这里有一个实现expl3

我还添加了一个可选参数(默认为空)用于生成不同的矩阵类型;对于相应的类型,可选参数应该是p、、或之中。bBvV

\documentclass{article}
\usepackage{amsmath}
\usepackage{xparse}

\setcounter{MaxMatrixCols}{20} % or maybe more

\ExplSyntaxOn
\NewDocumentCommand{\twolinematrix}{O{}m}
 {
  \twoline_matrix:nn { #1 } { #2 }
 }

\seq_new:N \l__twoline_i_seq
\seq_new:N \l__twoline_ii_seq

\cs_new_protected:Nn \twoline_matrix:nn
 {
  \seq_clear:N \l__twoline_i_seq
  \seq_clear:N \l__twoline_ii_seq
  \clist_map_function:nN { #2 } \twoline_add:n
  \begin{#1matrix}
  \seq_use:Nn \l__twoline_i_seq { & }
  \\
  \seq_use:Nn \l__twoline_ii_seq { & }
  \end{#1matrix}
 }
\cs_new_protected:Nn \twoline_add:n
 {
  \__twoline_add:w #1 \q_stop
 }
\cs_new_protected:Npn \__twoline_add:w #1/#2 \q_stop
 {
  \seq_put_right:Nn \l__twoline_i_seq { #1 }
  \seq_put_right:Nn \l__twoline_ii_seq { #2 }
 }
\ExplSyntaxOff

\begin{document}

\[
\twolinematrix{1/6, 2/7, 3/8, 4/9, 5/10}
\qquad
\twolinematrix[b]{1/6, 2/7, 3/8, 4/9, 5/10, 6/11, 7/12, 8/13, 9/14, 10/15}
\]

\end{document}

这和 wipet 的代码其实没什么区别。

  1. 我们清除行容器(这里是序列)
  2. 我们将给定的输入映射为逗号分隔的列表,调用内部函数\__twoline_add:w在斜线处拆分每个项目并将各部分添加到序列中
  3. 我们使用序列,放置&在项目之间

没有必要对第一项和其他项做不同的事情,这由 来处理\seq_use:Nn,它只添加之间项目。

与看似更紧凑的代码相比,其优点在于我们不需要重新发明轮子,而只需对逗号分隔列表的每个项目的操作给出适当的定义。

在此处输入图片描述

有关代码的更深入解释,请参阅:https://tug.org/TUGboat/tb39-1/tb121gregorio-expl3.pdf

答案2

例如,您可以使用以下代码:

\def\addto#1#2{\expandafter\def\expandafter#1\expandafter{#1#2}}
\def\autotwolinematrix#1{\def\firstrow{}\def\secondrow{}\atwolmA#1,/,}
\def\atwolmA#1/#2,{\ifx,#2,\pmatrix{\firstrow\cr\secondrow}\else
   \ifx\firstrow\empty \def\firstrow{#1}\def\secondrow{#2}\else
       \addto\firstrow{&#1}\addto\secondrow{&#2}\fi
   \expandafter \atwolmA \fi
}

test:
$$
  \autotwolinematrix{1/6, 2/7, 3/8, 4/9, 5/10}
$$
\bye

第一步:在循环中设置\firstrow和,同时读取参数。第二步:在中使用这些宏。\secondrow\pmatrix

答案3

在对齐内部,最好使用可扩展循环结构,因此使用expl3或这里我直接对其进行编码。

在此处输入图片描述

\documentclass{article}

\makeatletter
\def\autotwolinematrix#1{%
\begin{bmatrix}%
\firstrow,#1,\relax/%
\secondrow,#1,\relax/%
}
\def\firstrow#1,#2/{\ifx\relax#2\\\else\ifx\relax#1\relax\else&\fi#2\expandafter\firstrow\fi}
\def\secondrow#1,#2/{\ifx\relax#2#1\end{bmatrix}\else#1\ifx\relax#1\relax\else&\fi\expandafter\secondrow\fi}
\makeatother
\usepackage{amsmath}

\begin{document}

$\autotwolinematrix{1/6, 2/7, 3/8, 4/9, 5/10}$
\end{document}

相关内容