在 LaTeX 3 中转置部分填充的矩阵

在 LaTeX 3 中转置部分填充的矩阵

我正在研究 LaTeX 3 宏来获得如下所示的内容(我使用 ASCII 格式只是为了便于理解预期的输出):

x^2 - 2 = 0    or  4 x + 3 = 0  or  x - 3 = 0
x^2 = 2         |  4 x = - 3    |   x = 3
x = +/-sqrt(2)  |  x = - 3/4    |

API 看起来如下:

\orexpl{
    x^2 - 2 = 0      \\
    x^2 = 2          \\
    x = \pm \sqrt{2}
    ---
    4 x + 3 = 0       \\
    4 x = - 3         \\
    x = - \frac{3}{4}
    ---
    x - 3 = 0 \\
    x = 3
}

这是我拆分内容的起点---,但我正在寻找完成这项工作的建议。我的想法是构建可以在类似表格的环境中使用的代码,例如由 提出的代码nicematrix(实际上,我的小 M(not)WE 中的符号,;将被和替换&\\

\documentclass{article}

\ExplSyntaxOn
    \seq_new:N \l__pmbc_lines
    \seq_new:N \l__pmbc_cells

    \int_new:N \l__pmbc_nblines

    \NewDocumentCommand{\orexpl}{+m} {
        \seq_set_split:Nnn \l__pmbc_lines
                           { --- }
                           { #1 }

        \int_set:Nn \l__pmbc_nblines
                    { \seq_count:N \l__pmbc_lines }
    }
\ExplSyntaxOff

\begin{document}

NO HOLE

\orexpl{
    A1 \\ A2 \\ A3
    ---
    B1 \\ B2 \\ B3
    ---
    C1 \\ C2 \\ C3
}

Output wanted

A1 , B1 , C1 ;

A2 , B2 , C2 ;

A3 , B3 , C3 ;


\bigskip

WITH HOLES - CASE 1

\orexpl{
    A1 \\ A2 \\ A3
    ---
    B1
    ---
    C1 \\ C2
}

Output wanted

A1 , B1 , C1 ;

A2 , , C2 ;

A3 , , ;

\bigskip

WITH HOLES - CASE 2

\orexpl{
    A1
    ---
    B1 \\ B2
    ---
    C1 \\ C2 \\ C3
}

Output wanted

A1 , B1 , C1 ;

 , B2 , C2 ;

 , , C3 ;

\end{document}

答案1

expl3这是使用和{NiceMatrix}的解决方案nicematrix。您需要最新版本nicematrix(2021-04-08 的 v. 5.14)。

\documentclass{article}
\usepackage{nicematrix,tikz}

\ExplSyntaxOn
\seq_new:N \l__pmbc_lines_seq
\seq_new:N \l__pmbc_cells_seq
\int_new:N \l__pmbc_lines_int
\int_new:N \l__pmbc_cols_int

\cs_generate_variant:Nn \seq_set_split:Nnn { c n v }

\NewDocumentCommand { \orexpl } { +m } 
  {
    \seq_set_split:Nnn \l__pmbc_lines_seq { --- } { #1 }
    \int_set:Nn \l__pmbc_lines_int { \seq_count:N \l__pmbc_lines_seq }
    %
    % We create a sequence for each line called \l__pmbc_line_1_seq, \l__pmbc_line_2_seq, etc.
    % Recall that ##1 is the index of the loop: ##1 will vary from 1 to \l__pmbc_lines_int
    \int_step_inline:nn \l__pmbc_lines_int
      {
        \tl_set:cx { l__pmbc_line_ ##1 _tl } { \seq_item:Nn \l__pmbc_lines_seq { ##1 } } 
        \seq_set_split:cnv { l__pmbc_line_ ##1 _seq } { \\ } { l__pmbc_line_ ##1 _tl } 
      }
    % 
    % We compute in \l__pmbc_cols_int the maximum of the length of the previous sequences: it's the
    % number of columns of the input (the array given by the user).
    \int_step_inline:nn \l__pmbc_lines_int
      {
        \int_set:Nn \l_tmpa_int { \seq_count:c { l__pmbc_line_ ##1 _seq } }
        \int_compare:nNnT \l_tmpa_int > \l__pmbc_cols_int 
          { \int_set_eq:NN \l__pmbc_cols_int \l_tmpa_int }
      }
    \begin{NiceMatrix}
    %
    % Now, two imbricated loops. ##1 is the index of the first loop and ####1 is the index of the second loop.
    \int_step_inline:nn \l__pmbc_cols_int 
      { 
        \int_compare:nNnF ##1 > { \seq_count:c { l__pmbc_line_1_seq } }
          { \seq_item:cn { l__pmbc_line_1_seq } { ##1 } } 
        \int_step_inline:nnn 2 \l__pmbc_lines_int 
          {
            \int_compare:nNnTF ##1 > { \seq_count:c { l__pmbc_line_ ####1 _seq } }
              { & & }
              { 
                & 
    % The words "or" will be in a standalone column (the vertical rule below will be drawn by Tikz)
                \int_compare:nNnT { ##1 } = 1 { \text { or } }
                & 
                \seq_item:cn { l__pmbc_line_ ####1 _seq } { ##1 } 
              }
          }  
        \int_compare:nNnF \l__pmbc_cols_int = ##1 { \\ }
       }
    % 
    % We draw the vertical rules in the columns by using the PGF/Tikz constructed by {NiceMatrix}
    \CodeAfter
        \int_step_inline:nn { \l__pmbc_lines_int - 1 }
          { 
            \tikz \draw ( 2 -| \int_eval:n { 2 * ##1 } .5 ) 
                     -- (last -| \int_eval:n { 2 * ##1 } .5 ) ; 
          }
    \end{NiceMatrix}
  }
\ExplSyntaxOff
    
\begin{document}


$\orexpl{
    x^2 - 2 = 0      \\
    x^2 = 2          \\
    x = \pm \sqrt{2}
    ---
    4 x + 3 = 0       \\
    4 x = - 3         \\
    x = - \frac{3}{4}
    ---
    x - 3 = 0 \\
    x = 3 \\
}$

\bigskip
$\orexpl{A1 --- B1 --- C1 \\ C2 \\ C3}$

\bigskip
$\orexpl{A1--- B1 \\ B2 --- C1 \\ C2 \\ C3}$

\end{document}

与往常一样,nicematrix您需要进行多次编译(因为nicematrix在后台使用 PGF/Tikz 节点)。

上述代码的输出

答案2

这里,我使用分隔符listofitems来解析输入---。列表中的每个项目都可以直接用作堆栈。我实际上进行了嵌套解析,还读取了\\每个堆栈中的分隔符数量,并使用此信息来计算堆栈之间的规则深度。

我在其中一个示例中改变了列表深度,只是为了表明规则深度不是固定的,而是随着列表深度进行调整。

我还改变了堆栈的基线跳跃,规则会自动调整到设置。

[align]如果您希望提供制表符(在 之后,而不是 之前) ,请编辑以添加一个选项=。否则,对齐方式为左对齐。

\documentclass{article}
\usepackage{listofitems,tabstackengine}
\newcommand\orexpl[2][]{%
  \setsepchar{---/\\}
  \readlist*\myvecs{#2}%
  \def\listdepth{1}%
  \foreachitem\z\in\myvecs[]{%
    \ifnum\listlen\myvecs[\zcnt]>\listdepth\relax
      \xdef\listdepth{\listlen\myvecs[\zcnt]}%
    \fi
  }%
  \renewcommand\stackalignment{l}%
  \foreachitem\z\in\myvecs[]{%
    \ifnum\zcnt=1\relax\else\Shortunderstack[c]{\quad or\quad\\\rule
        {.4pt}{\numexpr\listdepth-1\relax\dimexpr\Lstackgap\relax}}\fi
    \ensurestackMath{\csname #1Longunderstack\expandafter
      \endcsname\expandafter{\z}}%
  }%
}
\begin{document}
\orexpl[align]{
    x^2 - 2 =& 0      \\
    x^2 =& 2          \\
    x =& \pm \sqrt{2}
    ---
    4 x + 3 =& 0       \\
    4 x =& - 3         \\
    x =& - \frac{3}{4}
    ---
    x - 3 =& 0 \\
    x =& 3
}

\bigskip
\orexpl{
    A123 \\ A2 \\ A3 \\ A4
    ---
    B1 \\ B2 \\ B3
    ---
    C1 \\ C2 \\ C3
}

\setstackgap{L}{.8\baselineskip}
\bigskip
\orexpl{
    A1 \\ A2 \\ A3
    ---
    B1
    ---
    C1 \\ C2
}

\setstackgap{L}{1.3\baselineskip}
\bigskip
\orexpl{
    A1
    ---
    B1 \\ B2
    ---
    C1 \\ C2 \\ C3
}
\end{document}

在此处输入图片描述

答案3

这是转置的基础:

\documentclass{article}
\usepackage{amsmath}

\ExplSyntaxOn

\NewDocumentCommand{\orexpl}{m}
 {
  \pmbc_orexpl:n { #1 }
 }

\cs_generate_variant:Nn \seq_set_split:Nnn { c }

\seq_new:N \l_pmbc_orexpl_lines_seq
\int_new:N \l_pmbc_orexpl_cols_int
\int_new:N \l_pmbc_orexpl_rows_int

% allocate at least three columns
\seq_new:c { l_pmbc_orexpl_col_1_seq }
\seq_new:c { l_pmbc_orexpl_col_2_seq }
\seq_new:c { l_pmbc_orexpl_col_3_seq }
% and three rows
\seq_new:c { l_pmbc_orexpl_row_1_seq }
\seq_new:c { l_pmbc_orexpl_row_2_seq }
\seq_new:c { l_pmbc_orexpl_row_3_seq }

\cs_new_protected:Nn \pmbc_orexpl:n
 {
  \seq_set_split:Nnn \l_pmbc_orexpl_lines_seq { --- } { #1 }
  \int_set:Nn \l_pmbc_orexpl_cols_int { \seq_count:N \l_pmbc_orexpl_lines_seq }
  \int_zero:N \l_pmbc_orexpl_rows_int
  % get the column data
  \seq_map_indexed_inline:Nn \l_pmbc_orexpl_lines_seq
   {
    \seq_clear_new:c { l_pmbc_orexpl_col_##1_seq }
    \seq_set_split:cnn { l_pmbc_orexpl_col_##1_seq } { \\ } { ##2 }
    \int_set:Nn \l_pmbc_orexpl_rows_int
     {
      \int_max:nn { \l_pmbc_orexpl_rows_int } { \seq_count:c { l_pmbc_orexpl_col_##1_seq } }
     }
   }
  % now transpose
  \int_step_inline:nn { \l_pmbc_orexpl_rows_int }
   {
    \seq_clear_new:c { l_pmbc_orexpl_row_##1_seq }
    \int_step_inline:nn { \l_pmbc_orexpl_cols_int }
     {
      \seq_put_right:cx { l_pmbc_orexpl_row_##1_seq }
       {
        \seq_item:cn { l_pmbc_orexpl_col_####1_seq } { ##1 }
       }
     }
   }
  % and build the array
  \begin{array}{ c *{ \int_eval:n { \l_pmbc_orexpl_cols_int - 1 } } { |c } }
  \int_step_function:nN { \l_pmbc_orexpl_rows_int } \__pmbc_orexpl_makerow:n
  \end{array}
 }

\cs_new_protected:Nn \__pmbc_orexpl_makerow:n
 {
  \seq_use:cn { l_pmbc_orexpl_row_#1_seq } { & } \\
 }

\ExplSyntaxOff

\begin{document}

\[
\orexpl{
    x^2 - 2 = 0      \\
    x^2 = 2          \\
    x = \pm \sqrt{2}
    ---
    4 x + 3 = 0       \\
    4 x = - 3         \\
    x = - \frac{3}{4}
    ---
    x - 3 = 0 \\
    x = 3
}
\]

\end{document}

在此处输入图片描述

使用“或”分隔符:

\documentclass{article}
\usepackage{amsmath,array}

\ExplSyntaxOn

\NewDocumentCommand{\orexpl}{m}
 {
  \group_begin:
  \setlength{\arraycolsep}{2em}
  \pmbc_orexpl:n { #1 }
  \group_end:
 }

\cs_generate_variant:Nn \seq_set_split:Nnn { c }
\cs_generate_variant:Nn \seq_map_indexed_inline:Nn { c }

\seq_new:N \l_pmbc_orexpl_lines_seq
\int_new:N \l_pmbc_orexpl_cols_int
\int_new:N \l_pmbc_orexpl_rows_int

% allocate at least three columns
\seq_new:c { l_pmbc_orexpl_col_1_seq }
\seq_new:c { l_pmbc_orexpl_col_2_seq }
\seq_new:c { l_pmbc_orexpl_col_3_seq }
% and three rows
\seq_new:c { l_pmbc_orexpl_row_1_seq }
\seq_new:c { l_pmbc_orexpl_row_2_seq }
\seq_new:c { l_pmbc_orexpl_row_3_seq }

\cs_new_protected:Nn \pmbc_orexpl:n
 {
  \seq_set_split:Nnn \l_pmbc_orexpl_lines_seq { --- } { #1 }
  \int_set:Nn \l_pmbc_orexpl_cols_int { \seq_count:N \l_pmbc_orexpl_lines_seq }
  \int_zero:N \l_pmbc_orexpl_rows_int
  % get the column data
  \seq_map_indexed_inline:Nn \l_pmbc_orexpl_lines_seq
   {
    \seq_clear_new:c { l_pmbc_orexpl_col_##1_seq }
    \seq_set_split:cnn { l_pmbc_orexpl_col_##1_seq } { \\ } { ##2 }
    \int_set:Nn \l_pmbc_orexpl_rows_int
     {
      \int_max:nn { \l_pmbc_orexpl_rows_int } { \seq_count:c { l_pmbc_orexpl_col_##1_seq } }
     }
   }
  % now transpose
  \int_step_inline:nn { \l_pmbc_orexpl_rows_int }
   {
    \seq_clear_new:c { l_pmbc_orexpl_row_##1_seq }
    \int_step_inline:nn { \l_pmbc_orexpl_cols_int }
     {
      \seq_put_right:cx { l_pmbc_orexpl_row_##1_seq }
       {
        \seq_item:cn { l_pmbc_orexpl_col_####1_seq } { ##1 }
       }
     }
   }
  % and build the array
  \__pmbc_orexpl_makerow_first:
  \begin{array}{ c *{ \int_eval:n { \l_pmbc_orexpl_cols_int - 1 } } { |c } }
  \tl_use:N \l_tmpa_tl \\
  \int_step_function:nnN { 2 } { \l_pmbc_orexpl_rows_int } \__pmbc_orexpl_makerow:n
  \end{array}
 }

\cs_new_protected:Nn \__pmbc_orexpl_makerow_first:
 {
  \tl_clear:N \l_tmpa_tl
  \seq_map_indexed_inline:cn { l_pmbc_orexpl_row_1_seq }
   {
    \int_compare:nTF { ##1 < \seq_count:c { l_pmbc_orexpl_row_1_seq } }
     { \tl_put_right:Nn \l_tmpa_tl { \multicolumn{1}{c!{\__pmbc_orexpl_or:}}{##2} & } }
     { \tl_put_right:Nn \l_tmpa_tl { ##2 } }
   }
 }

\cs_new_protected:Nn \__pmbc_orexpl_or:
 {
  \makebox[0pt]{\makebox[2\arraycolsep]{~or~}}
 }

\cs_new_protected:Nn \__pmbc_orexpl_makerow:n
 {
  \seq_use:cn { l_pmbc_orexpl_row_#1_seq } { & } \\
 }

\ExplSyntaxOff

\begin{document}

\[
\orexpl{
    x^2 - 2 = 0      \\
    x^2 = 2          \\
    x = \pm \sqrt{2}
    ---
    4 x + 3 = 0       \\
    4 x = - 3         \\
    x = - \frac{3}{4}
    ---
    x - 3 = 0 \\
    x = 3
}
\]

\end{document}

在此处输入图片描述

相关内容