Take the 2-minute tour ×
TeX - LaTeX Stack Exchange is a question and answer site for users of TeX, LaTeX, ConTeXt, and related typesetting systems. It's 100% free, no registration required.

Is it possible to use a loop to generate a list for a foreach loop? More specifically I want the following:

Consider the following answer to a question I asked some time ago: http://tex.stackexchange.com/a/38793/4011

It worked very well except if I define \alist as follows:

\def\alist{
    \foreach \i in {1,2,3}{
      \i/1,
      }4/1
    }

I get the following error:

ERROR: Undefined control sequence.

--- TeX said ---
\foreach ...reach \let \pgffor@assign@before@code 
                                                  =\pgfutil@empty \let \pgff...
l.38   \rectDiv{7}{5}{(1,1)}{(4,3)}{\alist}

Is there any way to fix this?

Edit:

Full example:

\documentclass{article}
\usepackage{tikz}
\usetikzlibrary{calc}
  \def\rectDiv#1#2#3#4#5{%#columns, #rows, rectangle start, rectangle end, list of elements to fill
    \begin{tikzpicture}
      \draw #3 rectangle #4;
      \path #3;
      \pgfgetlastxy{\firstx}{\firsty}
      \path #4;
      \pgfgetlastxy{\secondx}{\secondy}
      \pgfmathsetlengthmacro{\xdiff}{\secondx-\firstx}
      \pgfmathsetlengthmacro{\ydiff}{\secondy-\firsty}
      \pgfmathsetlengthmacro{\myxstep}{\xdiff/#1}
      \pgfmathsetlengthmacro{\myystep}{\ydiff/#2}
      \foreach \x in {1,...,#1}{
        \draw ($#3 +\x*(\myxstep,0)$) -- ($#3 +(0,\ydiff) +\x*(\myxstep,0)$);
      }
      \foreach \y in {1,...,#2}{
        \draw ($#3 +\y*(0,\myystep)$) -- ($#3 +(\xdiff,0) +\y*(0,\myystep)$);
      }
      \edef\temp{\noexpand\foreach \noexpand\i/\noexpand\j in {#5}}
      \temp{
        \path[fill=blue!20,draw] ($#3 + (\i*\myxstep,\j*\myystep)$) rectangle ($#3 + (\i*\myxstep,\j*\myystep) + (\myxstep,\myystep)$);
      }
    \end{tikzpicture}
  }
\begin{document}
  \rectDiv{7}{5}{(1,1)}{(4,3)}{0/0,1/1,2/0,5/3}

  \def\list{1/0}
  \rectDiv{7}{5}{(1,1)}{(4,3)}{\list}

  \rectDiv{7}{5}{(1,1)}{(4,3)}{\list,2/0,5/3}

  \def\alist{
    \foreach \i in {1,2,3}{
      \i/1,
      }4/1
    }

   \alist

   \rectDiv{7}{5}{(1,1)}{(4,3)}{\alist}  %this doesn't  work

\end{document}
share|improve this question
add comment

1 Answer

up vote 7 down vote accepted

Your problem is that you wrote

\edef\temp{\noexpand\foreach \noexpand\i/\noexpand\j in {#5}}

% Here is what #5 is in \temp:
\def\alist{
\foreach \i in {1,2,3}{
  \i/1,
  }4/1
}

which requires that the stuff in the braces be "fully expandable". Alas, \foreach is not expandable, and it is part of \alist. So when \temp is defined, it expands "as much as possible" and hits some non-expandable part of the code of \foreach, which in this case is \let \pgffor@assign@before@code = ...; \let is an assignment, and not expandable, so is not changed by \edef. Thus, the assignment is not actually performed, and \edef goes on to try to interpret the following control sequence \pgffor@assign@before@code directly. Not surprisingly, it is not defined, since it was the \let that is supposed to define it, so you get an error.

To do this, you have to create a macro that contains the output of \alist. For example,

\gdef\alist{}
\foreach \i in {1,2,3} {
 \xdef\alist{\alist \i/1,}
}
\xdef\alist{\alist 4/1}

Then you can use \alist directly instead of \temp. (I have used global assignments for \alist because \foreach executes its contents in a group.)

share|improve this answer
    
Is there a way to do this without using global macros? –  Adam Crume Oct 18 '13 at 4:32
    
Not with \foreach. It acts in a group, so you have to break out with global macros. –  Ryan Reich Oct 18 '13 at 11:40
add comment

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

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