7

I'm trying to create a matrix using nested \foreach loops. I tried following the example I found in a previous question, but I keep getting errors.

Here is the code I tried to run:

\documentclass{article}
\usepackage{etoolbox}
\usepackage{tikz}
\usetikzlibrary{matrix}

\begin{document}
\let\mymatrixcontent\empty
\newcommand{\row}[1]{
  \foreach \i in {0,...,5} {
    \xappto\mymatrixcontent{\expandonce{
      \node {\i}; & 
    }}
  }
  \xappto\mymatrixcontent{\\}
}
\row{1}

\begin{tikzpicture}
  \matrix[matrix of nodes]{
    \mymatrixcontent
  };
\end{tikzpicture}
\end{document}

I'm getting an error:

! Undefined control sequence.
\\  ->\let \reserved@e 
                       \relax \let \reserved@f \relax \@ifstar {\let \reserv...
l.16 \row{1}

I noticed that this error occurs only after adding the new row after the \foreach loop. Is there a way to avoid it?

EDIT: I completed the example.

0
13

If you do

\let\mymatrixcontent\empty
\newcommand{\row}{%
  \foreach \i in {0,...,5} {%
    \gappto\mymatrixcontent{\node{\i}; \&}%
    }%
  \gappto\mymatrixcontent{\\}%
}
\row

(using \& is better because of problems with "naked" & tokens; percusse's answer tells how to cope with this when building the matrix) then \mymatrixcontent will expand to

\node{\i}; \& \node{\i}; \& \node{\i}; \& \node{\i}; \& \node{\i}; \&\

and the current definition of \i will be used, which is "print a dotless i", because \i will expand to the successive values only during the action of \foreach. So what's needed is the expansion of \i during the action of \foreach:

\let\mymatrixcontent\empty
\newcommand{\row}{%
  \foreach \i in {0,...,5} {%
    \begingroup\edef\x{\endgroup
       \noexpand\gappto\noexpand\mymatrixcontent{\noexpand\node{\i}; \&}}\x
    }%
  \gappto\mymatrixcontent{\\}%
}
\row

However one has to pay close attention when using \edef: not all tokens are allowed inside the replacement text and those which we want to get as themselves need to be prefixed by \noexpand. In this particular case, where \i is the only token to be expanded, a different method can be used

\let\mymatrixcontent\empty
\newcommand{\row}{%
  \foreach \i in {0,...,5} {%
    \expandafter\gappto\expandafter\mymatrixcontent\expandafter{%
      \expandafter\node\expandafter{\i} \&}}%
    }%
  \gappto\mymatrixcontent{\\}%
}
\row

because the \expandafter chain will cause the expansion of \i before \gappto is executed.


A different approach could be with expl3:

\documentclass{article}
\usepackage{xparse}
\usepackage{tikz}
\usetikzlibrary{matrix}

\ExplSyntaxOn
\NewDocumentCommand{\row}{mmm}
 {%#1 is the macro to define, #2 is the final number, #3 is the code
  \tl_clear_new:N #1
  \int_step_inline:nnnn { 0 } { 1 } { #2 }
   {
    \tl_put_right:Nn #1 { #3 }
   }
  \tl_put_right:Nn #1 { \\ }
 }
\ExplSyntaxOff

\begin{document}
\row{\mymatrixcontent}{5}{\node { #1 }; \& }

\begin{tikzpicture}
  \matrix[matrix of nodes,ampersand replacement=\&]{
    \mymatrixcontent
  };
\end{tikzpicture}
\end{document}

In the third argument to \row, #1 is successively evaluated as 0,...,5 (because 5 is the second argument).

enter image description here

11
  • I wasn't able to compile your first solution. I got Too many }'s.
    – haggai_e
    Mar 12 '12 at 6:42
  • 2
    Sorry to bother you, but there's still an extra brace in the first solution (the second code segment). I would have deleted it myself, but SO doesn't allow me to do a single character edit.
    – haggai_e
    Mar 12 '12 at 8:12
  • 1
    @PeterGerdes Use the second approach
    – egreg
    Feb 11 '21 at 13:22
  • 1
    @PeterGerdes If you place \row inside the tikzpicture, then \mymatrixcontent would be local to it.
    – egreg
    Feb 12 '21 at 9:26
  • 1
    @PeterGerdes Yes, the expl3 version; the \foreach based versions need global assignments.
    – egreg
    Feb 12 '21 at 10:26
6

As Martin wrote in the linked answer it's working with \gappto command. Here is an example that works for me. I also changed the ampersand since it's always problematic to put a lonely & into the bowels of expanding macros :)

\documentclass{article}
\usepackage{etoolbox}
\usepackage{tikz}
\usetikzlibrary{matrix}

\begin{document}
\let\mymatrixcontent\empty
\newcommand{\row}[1]{
  \foreach \i in {0,...,5} {
    \gappto\mymatrixcontent{\expandonce{
     A  \& 
    }}
  }
  \gappto\mymatrixcontent{\\}
}
\row{1}

\begin{tikzpicture}
  \matrix (a) [matrix of nodes,ampersand replacement=\&]{
    \mymatrixcontent
  };
    \draw (a-1-1) -- (a-1-5);
\end{tikzpicture}

\end{document}

code output

3
  • Thanks! I had an error when I used \gappto at first, but I guess it was unrelated.
    – haggai_e
    Mar 11 '12 at 11:28
  • There's still a problem with this method. For some reason if I put \i after the A, the result is A 1 in all the cells.
    – haggai_e
    Mar 11 '12 at 11:41
  • @haggai_e Hmm, that's not 1 but iota, dotless i character. Apparently, \i becomes a command rather than the argument of foreach loop. I'll try to fix it.
    – percusse
    Mar 11 '12 at 12:01
2

enter image description here

\documentclass{article}
\usepackage{tikz}
\usetikzlibrary{matrix}
\usepackage{etoolbox}

\begin{document}
\begin{tikzpicture}
\let\mymatrixcontent\empty
\foreach \row in {1,...,8}{%%
\foreach \col in {1,...,5}{%
\xappto\mymatrixcontent{r\row c\col \expandonce{\&}}
}%
\gappto\mymatrixcontent{\\}
}%%

\matrix[matrix of nodes, ampersand replacement=\&,
column sep=2ex,  label={Matrix}
] (m){
\mymatrixcontent 
};
\end{tikzpicture}
\end{document}

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.