11

I am learning \foreach to see if it will work for what I want to do. I can't figure why the following does not generate the expected output.

MWE

\documentclass[12pt,titlepage]{article}
\usepackage{pgffor}
\setlength\parindent{0pt}

\def\mydata{
{1,2},
{3,4}
}
\begin{document}

\foreach \x in \mydata
{
   now starting new entry....\\
   \foreach \y in \x
   {
      \y \\
   }  
}
\end{document}

The above generate

Mathematica graphics

I was expecting the second list {3,4} to also show on a separate line.

What Am I doing wrong?

TL 2014

Update

I found that the problem is that the last entry has to be on same line as the closing }, like this

\def\mydata{
{1,2},
{3,4},
{5,6}}

If the above was written as

\def\mydata{
{1,2},
{3,4},
{5,6}
}

Then same problem will show up.

Nasser
  • 20,220

3 Answers3

7

With some debug output:

\documentclass[12pt,titlepage]{article}
\usepackage{pgffor}
\setlength\parindent{0pt}

\def\mydata{
{1,2},
{3,4}
}
\begin{document}

\foreach \x in \mydata
{
   now starting new entry [\texttt{\detokenize\expandafter{\x}}]\\
   \foreach \y in \x
   {
      \y \\
   }
}
\end{document}

Debug output

As can be seen, the parsing of the comma separated list is not perfect, some spaces are removed, the spaces at the begin of the entry, But the spaces at the end of the entry remain. In the second case, the value does not have outer braces because of the trailing space and the inner \foreach will see a value instead of a list.

This can be fixed by commenting the line end.

\documentclass[12pt,titlepage]{article}
\usepackage{pgffor}
\setlength\parindent{0pt}

\def\mydata{
{1,2}, 
{3,4}%
}
\begin{document}

\foreach \x in \mydata
{
   now starting new entry [\texttt{\detokenize\expandafter{\x}}]\\
   \foreach \y in \x
   {
      \y \\
   }
}
\end{document}

Fixed result

BTW, the latest \\ will cause an "Underfull \hbox" warning. For example, this can be fixed by:

\documentclass[12pt,titlepage]{article}
\usepackage{pgffor}
\setlength\parindent{0pt}

\def\mydata{
{1,2},
{3,4}%
}

\newif\ifprevious

\begin{document}

\global\previousfalse
\foreach \x in \mydata
{
   \ifprevious\\\fi
   \global\previoustrue
   now starting new entry [\texttt{\detokenize\expandafter{\x}}]%
   \foreach \y in \x
   {
      \\\y
   }
}
\end{document}

Remark: Global assignments are necessary, because \foreach puts the loop body into a group.

Heiko Oberdiek
  • 271,626
3

You have spurious spaces

\documentclass[12pt,titlepage]{article}
\usepackage{pgffor}
\setlength\parindent{0pt}

\def\mydata{{1,2},{3,4}}
\begin{document}

\foreach \x in \mydata
{
   now starting new entry....\\
   \foreach \y in \x
   {
      \y \\
   }  
}
\end{document}
Manuel
  • 27,118
  • Actually I just found the problem. It is the last carriage return before the last entry ! The last entry has to be on same line as the closing }. I'll add an example now. – Nasser Jun 25 '15 at 00:47
  • No, the problem is that spaces aren't ignored around commas like in other cases (e.g., TikZ options), in this case you got luck that you can leave spaces after the comma, but you can't before (try \def\mydata{{1,2} , {3,4}}). – Manuel Jun 25 '15 at 00:49
3

This is not a direct answer, but I want just to mention that there are other solutions, for example xintFor from xinttools library.

\documentclass[preview, border=7mm]{standalone}
\usepackage{xinttools}
% spaces before and after commas are deleted
\def\mydata{
{1,2},
{3,4}
}

\begin{document}
  \xintFor #1 in {\mydata} \do {
     now starting new entry....\\
    \xintFor #2 in {#1} \do {
      #2 \\
    }
  }
\end{document}

enter image description here

Kpym
  • 23,002