5

This answer shows me how I can handle an arbitrary number of arguments. I have adapted it a bit to my purpose:

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

The above macro should take input like this as an example: \autotwolinematrix{1/6, 2/7, 3/8, 4/9, 5/10}.

I have become stuck because, normally, if you want to create a matrix (assuming you have amsmath loaded), you would so something like:

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

So, this suggests that you'd need to have logic that knows when you are about to be done with the element pairs, because you have to put the \\. I think if we are programmatically generating the matrix, it would be better to think of it like this:

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

where #1 & #2 & #3 & #4 & #5 \\ #6 & #7 & #8 & #9 & #10 is the string that has to be auto-generated within the body of our macro. Our macro gets input pairwise, so we have to generate this string given pairs. Okay, then in the body of our macro, we should have two variables: call it \firstrow and \secondrow.

The \firstrow and \secondrow should be built up sequentially, given each pair of elements, and then finally a variable called \matrixbody should be generated like so:

\matrixbody = \firstrow \\ \secondrow

Can you help me put these thoughts together?

0
5

Perhaps less attractive than hand-made recursive macros, here is an implementation in expl3.

I also added an optional argument (default empty) for producing different matrix types; the optional argument should be among p, b, B, v or V, for the corresponding type.

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

This isn't really so different from wipet's code.

  1. We clear the containers for the rows (here sequences)
  2. We map the input given as a comma separated list, calling the internal function \__twoline_add:w that splits each item at the slash and adds the pieces to the sequences
  3. We use the sequences, placing & between items

There is no need to do different things for the first item and the others, this is taken care of by \seq_use:Nn, which only adds between items.

The advantage over the seemingly more compact code is that we don't need to reinvent the wheel, but just to give an appropriate definition for the action on each item of the comma separated list.

enter image description here

For a deeper explanation of the code, see this: https://tug.org/TUGboat/tb39-1/tb121gregorio-expl3.pdf

1
  • wow...look ma! latex3e! – user89 Sep 25 '17 at 1:38
4

For example, you can use this code:

\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

First step: \firstrow and \secondrow are set in the loop while parameters are read. Second step: these macros are used in \pmatrix.

0
3

Inside alignments it is best to use an expandable loop construct, so using expl3 or here I just code it directly.

enter image description here

\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}
2
  • Your second loop ends by \ifx\relax\else ...do something\fi. This was not probably your intend... Moreover, there is empty column at the end of the matrix. – wipet Sep 24 '17 at 20:32
  • @wipet the \ifx was OK I think but I did have an extra & as you said. Thanks. Fixed now (not as elegant as it was but I wanted to keep the expandable loop to keep the distinction between the answers:-) used bmatrix to make the column count clearer. – David Carlisle Sep 24 '17 at 21:33

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.