# How can I write a nested loop if the inner loop doesn't always have the same number of repetitions?

I am writing a questionnaire. It lists 16 software features, and the participants should answer things like "I find this feature: Very important - Somewhat important - Not at all important" once for each feature.

The wording of the features and of each question changes a lot while we are working on the questionnaire, so it would be insane to format everything per hand and include the changes over and over. Instead, I created a command called \featureanswers which takes one argument (the feature description) and prints the questions about the features. I use this command with a pgffor loop to create the questionnaire.

Now, my boss decided that we have to change the numbering. Because Feature 7 and Feature 8 are mutually exclusive, they should be numbered Feature 7a and Feature 7b instead. I can't find a good solution for this case. I tried writing a nested loop, but only succeeded in writing one which expects the same number of elements for each run of the inner loop.

Any ideas how I can handle that automatically? I know I can split it to two loops (before and after 7) and print 7a and 7b on their own, but I would like a more elegant solution, which can handle future changes to the other features.

This is the code for the current version. It assumes all features are the same (no 7a and 7b).

\documentclass[a4paper,12pt]{article}
\usepackage{pgffor}
\usepackage{amssymb}

\def\allfeatures{\fone,\ftwo,\fthree,\ffour,\ffive,\fsix,\fseven,\feight,\fnine,\ften,\feleven,\ftwelve,\fthirteen,\ffourteen,\ffifteen,\fsixteen}

\def\fone{redacted}
\def\ftwo{redacted}
\def\fthree{redacted}
\def\ffour{redacted}
\def\ffive{redacted}
\def\fsix{redacted}
\def\fseven{redacted}
\def\feight{redacted }
\def\fnine{redacted}
\def\ften{redacted}
\def\feleven{redacted}
\def\ftwelve{redacted}
\def\fthirteen{redacted}
\def\ffourteen{redacted}
\def\ffifteen{redacted}
\def\fsixteen{redacted}

\newcounter{featurecounter}
\setcounter{featurecounter}{0}
{
\stepcounter{featurecounter}

\vspace{18pt}
{\bf Feature} \arabic{featurecounter} {#1}
\begin{enumerate}
\parbox{8cm}{\item I can envision a way this feature will be implemented.}
\begin{tabular}{c c c c c}
really well & & unsure & & not at all \\
$\square$ & $\square$ & $\square$ & $\square$ & $\square$ \\
\end{tabular}

\parbox{4.5cm}{\item I think this feature is: }
\begin{tabular}{c c c c c}
very important & & slightly important & & not important \\
$\square$ & $\square$ & $\square$ & $\square$ & $\square$ \\
\end{tabular}

\end{enumerate}
}

\begin{document}

\foreach \featureB in \allfeatures{
}

\end{document}

-
How you thought about how you want to be able to specify when to combine them into an a, b question? –  Peter Grill Mar 8 '12 at 19:30
@PeterGrill this is one of the problems I ran into. I guess it will depend on what the final solution will be. As far as I know, I can't create a "nested" list. But maybe it can be somehow indicated when creating the \allfeatures list? –  rumtscho Mar 8 '12 at 19:40
I just had an idea: If I don't number the features using a counter, but define a new sequence of feature numbers to be printed before each feature. Then I can define 7a and 7b in it. But then, I have to somehow tell the foreach loop to get me the x-th element of the list of featurenumbers for the x-th feature. –  rumtscho Mar 8 '12 at 19:43
Ok, I think my solution provides a flexible way of grouping. –  Peter Grill Mar 8 '12 at 19:52
I will wait with choosing an accepted answer until I have found out how all three work. Until now, I only looked into @PeterGrill 's in depth, and I don't know enough LaTeX to understand the others. Will have to read about the commands they used first. –  rumtscho Mar 8 '12 at 21:39

The syntax for inputting the questions seems good:

\features{
1/First question \\
2/Second question \\
3/Third question \\
4a/Fourth question A \\
4b/Fourth question B \\
5/Fifth question
}


The number can be anything you want. Complete example with the code:

\documentclass[a4paper,12pt]{article}

\usepackage{amssymb}
\usepackage{xparse}
\NewDocumentCommand{\featureprint}{ >{\SplitList{/}} m }
{\featureprintaux #1}
\NewDocumentCommand{\featureprintaux}{ m m }
{\par
\vspace{18pt}
\textbf{Feature} #1. #2
\begin{enumerate}
\item\parbox[t]{8cm}{I can envision a way this feature will be implemented.}
\begin{tabular}[t]{c c c c c}
really well & & unsure & & not at all \\
$\square$ & $\square$ & $\square$ & $\square$ & $\square$ \\
\end{tabular}
\item\parbox[t]{4.5cm}{I think this feature is: }
\begin{tabular}[t]{c c c c c}
very important & & slightly important & & not important \\
$\square$ & $\square$ & $\square$ & $\square$ & $\square$ \\
\end{tabular}
\end{enumerate}
}
\ExplSyntaxOn
\NewDocumentCommand{\features}{ +m }
{
\seq_set_split:Nnn \l_feat_features_seq { \\ } { #1 }
\seq_map_inline:Nn \l_feat_features_seq
{
\featureprint { ##1 }
}
}
\ExplSyntaxOff

\begin{document}

\features{
1/First question \\
2/Second question \\
3/Third question \\
4a/Fourth question A \\
4b/Fourth question B \\
5/Fifth question
}

\end{document}


-

You need to think first about the data structure that you are using:

Firstly you have a list holding features:

\def\alist{1,2,3,4,5,6,7,7a,8,9,10}


Plain numbers point to macros that typeset say Line A and the ones with a letter to macros that typeset Line B.

Note the list just holds pointers to macros that hold the information, it does not hold the macros. Let us create the macros automatically:

\def\Z{This is line A}
\def\ZZ{This is line B}

\newcounter{ctr}
\setcounter{ctr}{0}
\loop
\ifnum\thectr<11
\expandafter\edef\csname feature@\thectr\endcsname{Feature \thectr\ Redacted\par \Z\par\Z\par }%
\stepcounter{ctr}
\repeat
\expandafter\edef\csname feature@7a\endcsname{Feature 7a Redacted\par \ZZ\par\ZZ\par }%


Next we use a loop to access them:

\@for\next:=1,2,3,4,5,6,7,7a,8,9,10\do{%
\csname feature@\next\endcsname
}


Q.E.D.

Here is the full MWE.

\documentclass{article}
\makeatletter
\def\Z{This is line A}
\def\ZZ{This is line B}

\newcounter{ctr}
\setcounter{ctr}{0}
\loop
\ifnum\thectr<11
\expandafter\edef\csname feature@\thectr\endcsname{Feature \thectr\ Redacted\par \Z\par\Z\par }%
\stepcounter{ctr}
\repeat
\long\expandafter\edef\csname feature@7a\endcsname{Feature 7a Redacted\par \ZZ\par\ZZ\par }%

\begin{document}
\@for\next:=1,2,3,4,5,6,7,7a,8,9,10\do{%
\csname feature@\next\endcsname
}
\end{document}

-

Here is one way of doing this: In \allfeatures an element itself can be a list which means to add the part (a), (b), etc... Note that element 7 is {\fsevenA,\fsevenB}.

Since the input strings can have commas in them, and we are using the comma as a list separator, this needs special handling. A solution I found was to use a macro for the comma in the text:

\newcommand*{\Comma}{{,} }


Perhaps with some \catcode trickery this can be avoided, but this does appear to work.

Below I have commented out the \enumerate containing the two \parbox as that is not needed to show the problem being addressed here:

## Notes:

• The ? do not seem to pose any special issues.
• I used the xstring package to test the number of members in the current list and add the alphabetic labels only when there is more than one member of the list.
• This necessitated moving the \stepcounter functionality to the \foreach loops.

## Code:

\documentclass[a4paper,12pt]{article}
\usepackage{pgffor}
\usepackage{amssymb}
\usepackage{xstring}

\newcommand*{\Comma}{{,} }%

\def\allfeatures{\fone,\ftwo,\fthree,\ffour,\ffive,\fsix,{\fsevenA,\fsevenB},{\feight},\fnine,\ften,\feleven,\ftwelve,\fthirteen,\ffourteen,\ffifteen,\fsixteen}

\def\fone{This is the first feature}
\def\ftwo{This is the second feature}
\def\fthree{This is the third feature\Comma and happens to have a comma}
\def\ffour{This is the fourth feature}
\def\ffive{This is the fifth feature}
\def\fsix{This is the sixth feature}
\def\fsevenA{This is the first part of the seventh feature\Comma and has a ? and a comma}%
%%Now, there are two features here, that are
\def\fsevenB{This is the second part of the seventh feature}%  provided as one group in
%the list of \allfeatures .
\def\feight{This is the eighth feature\Comma maybe?}
\def\fnine{This is the ninth feature}
\def\ften{This is the tenth feature}
\def\feleven{This is the eleventh (I think?) feature}
\def\ftwelve{This is the twelveth feature}
\def\fthirteen{This is the thirteenth feature}
\def\ffourteen{This is the fourteenth feature}
\def\ffifteen{This is the fifteenth feature}
\def\fsixteen{This is the sixteenth feature}

\newcounter{featurecounter}
\newcounter{featureSubCounter}
\setcounter{featurecounter}{0}
\setcounter{featureSubCounter}{0}
\IfEq{#1}{0}{\arabic{featurecounter}}{\arabic{featurecounter}(\alph{featureSubCounter})}%
\vspace{18pt}%
{\bfseries ~Feature}  {#2}%

% Comment this out as output can still show that the problem being solved here works
%    \begin{enumerate}%
%         \parbox{8cm}{\item I can envision a way this feature will be implemented.}%
%        \begin{tabular}{c c c c c}%
%            really well & & unsure & & not at all \\%
%            $\square$ & $\square$ & $\square$ & $\square$ & $\square$ \\%
%        \end{tabular}%
%
%        \parbox{4.5cm}{\item I think this feature is: }%
%            \begin{tabular}{c c c c c}%
%                very important & & slightly important & & not important \\%
%                $\square$ & $\square$ & $\square$ & $\square$ & $\square$ \\%
%            \end{tabular}%
%    \end{enumerate}%
}

\begin{document}
\foreach \featureBList in \allfeatures{%
\StrCount{\featureBList}{,}[\NumberOfItems]%
\stepcounter{featurecounter}%
\setcounter{featureSubCounter}{0}%
\foreach \featureB in \featureBList{%
\stepcounter{featureSubCounter}%
}%
}
\end{document}

-
@MarcoDaniel: Done. But please feel free to make the changes, especailly since they are not related to the thrust of the question. I totally agree that we should try to keep the answers as best as possible, so thanks for pointing that out. –  Peter Grill Mar 8 '12 at 19:58
Very interesting. The recognition on comma won't work, because each feature description is a sentence, and may contain a comma itself. I'll try to expand the solution to somehow get it right. –  rumtscho Mar 8 '12 at 19:58
@rumtscho: You could probably just group them again: ...{\fsix},{{\fsevenA},{\fsevenB}},{\feight}.... Try it and provide a new MWE if this does not work. –  Peter Grill Mar 8 '12 at 20:02
No, it doesn't work. But I wrote my own version inspired by yours (see my own answer); I didn't know about the xstring package before, so it was already very valuable information. –  rumtscho Mar 8 '12 at 21:40
@rumtscho: It works if you replace the , with \Comma which is defined as \newcommand*{\Comma}{{,} }. Have updated the solution to illustrate this. –  Peter Grill Mar 9 '12 at 0:44

The answer provided by Peter Grill was interesting, but it broke if a feature contained a comma. Based on his answer, I created my own version. It looks a bit clumsy, but it works. I especially dislike the part where it has to check if the subfeature starts with a, so it doesn't rewind the counter.

As you can see, neither the comma (which isn't used for control structures any more) nor a question mark (which I use for control now) break it.

I know that the formatting is not very nice yet, but I will refine it later, after the content is decided.

\documentclass[a4paper,12pt]{article}
\usepackage{pgffor}
\usepackage{amssymb}
\usepackage{xstring}

%We have to know which feature gets a special number. For this, we use a prefix. 0? for
features with no special number, a? for the first subfeature of a question, then
alphabetically for the next subfeatures.
\def\allfeatures{0?\fone,0?\ftwo,0?\fthree,0?\ffour,0?\ffive,0?\fsix,a?\fsevenA,b?
\fsevenB,0?\feight,0?\fnine,0?\ften,0?\feleven,0?\ftwelve,0?\fthirteen,0?\ffourteen,0?
\ffifteen,0?\fsixteen}

\def\fone{This is the first feature}
\def\ftwo{This is the second feature}
\def\fthree{This is the third feature, and happens to have a comma}
\def\ffour{This is the fourth feature}
\def\ffive{This is the fifth feature}
\def\fsix{This is the sixth feature}
\def\fsevenA{This is the first part of the seventh feature, and has a ? and a comma}%
Now, there are two features here, that are
\def\fsevenB{This is the second part of the seventh feature}%  provided as one group in
the list of \allfeatures .
\def\feight{This is the eighth feature, maybe?}
\def\fnine{This is the ninth feature}
\def\ften{This is the tenth feature}
\def\feleven{This is the eleventh (I think?) feature}
\def\ftwelve{This is the twelveth feature}
\def\fthirteen{This is the thirteenth feature}
\def\ffourteen{This is the fourteenth feature}
\def\ffifteen{This is the fifteenth feature}
\def\fsixteen{This is the sixteenth feature}

\newcounter{featurecounter}
\setcounter{featurecounter}{0}
\arabic{featurecounter}#1.\ %
\vspace{18pt}%
{\bfseries ~Feature}  {#2}%
\begin{enumerate}%
\parbox{8cm}{\item I can envision a way this feature will be implemented.}%
\begin{tabular}{c c c c c}%
really well & & unsure & & not at all \\%
$\square$ & $\square$ & $\square$ & $\square$ & $\square$ \\%
\end{tabular}%

\parbox{4.5cm}{\item I think this feature is: }%
\begin{tabular}{c c c c c}%
very important & & slightly important & & not important \\%
$\square$ & $\square$ & $\square$ & $\square$ & $\square$ \\%
\end{tabular}%
\end{enumerate}%
}

\begin{document}
\foreach \featureB in \allfeatures{%
\stepcounter{featurecounter}%
\IfBeginWith{\featureB}{0?}{
}
{
\IfBeginWith{\featureB}{a?}
{}