16

I am trying to create a loop within another loop using some of the constructs in etoolbox but I am not sure how to create that.

I want to get the output like in C.

pseudo code

for (i in the list) {            
    for (j in the list) {  
        print(i,j)
    }
}

LaTeX code

For example I do not know how to achieve the same functionality as above using the \dolistcsloop construct in LaTeX.

\documentclass{minimal}  
\usepackage{etoolbox}

\begin{document}  
\def\mylist{}  
\forcsvlist{\listadd\mylist}{1,2,3}

 % Not sure how to acheive the double looping as the source code above using the \dolistloop construct of etoolbox.   


\end{document}
4
  • Your code is wrong. It has only one loop at the moment and it's an unclear what you want to achieve.
    – user31729
    Jul 21 '15 at 5:31
  • The \dolistloop approach requires a redefined \do command.
    – user31729
    Jul 21 '15 at 6:11
  • Please not that \foreach for pgffor package could be easier by far, but this depends on the requirements
    – user31729
    Jul 21 '15 at 6:18
  • 1
    minimal document class is not meant for the end-user. Have a look at tex.stackexchange.com/questions/42114/…
    – percusse
    Jul 21 '15 at 6:22
12

This shows one way how to use a nested loop with etoolbox

\forlistloop has two parameters: The second one is the list name, the first one is a list processor, i.e. what is to be done inside the loop. The best idea is to use a \newcommand macro which is expandable.

This list processing macro can have a 'arbitrary' number of arguments, but the last one is always used to handle of the current list element, which is determined by \forlistloop.

In a nested \forlistloop approach, this requires for example two list processors macros. The outer one uses the internal \forlistloop and the internal \grabfrominnerlist macro.

Please note, that there is no general rule how to do nested looping -- the typesetting determines the nesting/looping order (amongst other TeX specific features such as grouping etc.)

\documentclass{article}
\usepackage{etoolbox}

\newcounter{rowcounter}
\newcounter{columncounter}
\newcounter{innercounter}

\newcommand{\addwithcounting}[3]{%
  \stepcounter{#1}
  \listadd{#2}{#3}
}

\newcommand{\grabfromouterlist}[2]{%
  \setcounter{innercounter}{0}% Reset the inner counter
  \forlistloop{\grabfrominnerlist{#2}}{#1} \\  % use the 2nd argument which is fed from the outer loop actually and process the list given as 1st argument. 
}

\newcommand{\grabfrominnerlist}[2]{%
  \stepcounter{innercounter}%
  \ifnumless{\value{innercounter}}{\value{columncounter}}{%
  a_{#1#2} & % typeset the matrix element with index of row and column number
  }{%
  a_{#1#2}% Final column, do not add a & character
  }%
}


\usepackage{mathtools}

\begin{document}  

\def\mycolumnlist{}  
\def\myrowlist{}  

\forcsvlist{\addwithcounting{rowcounter}{\myrowlist}}{1,2,3,4,5,6,7,8,9}
\forcsvlist{\addwithcounting{columncounter}{\mycolumnlist}}{1,2,3,4,5,6,7,8}

$\begin{pmatrix}
  \forlistloop{\grabfromouterlist{\mycolumnlist}}{\myrowlist} 
\end{pmatrix}$


$\begin{Bmatrix}
  \forlistloop{\grabfromouterlist{\mycolumnlist}}{\myrowlist} 
\end{Bmatrix}$

\end{document}

enter image description here

Please note that you can't use more than 10 columns here (without some more work), but this not a problem of etoolbox but of the underlying matrix environment.

Edit

The O.P. sent me a mail with some questions, so I'll try to answer here with some 'extended' version.

The \forlistloop command has two arguments: The first one is the list processing one, the second is the command sequence for the list.

\forlistloop does nothing more (but not less too) than to sweep through the list elements, cracking the list into its list elements. During the sweep this element is given to the list processing macro as the last argument. So, for example, if the list should just be shown, a processor naming \showlist would be sufficient.

\newcommand{\showlist}[1]{%
#1 %  <---- this is handled over by \forlistloop

}

\forlistloop{\showlist}{\mylist} % Does the job

Now, the list processor can have of course more than just argument, but the data from the list always enters from the right to the left side, so it's always the last argument that gets the list element from \forlistloop or \forlistcsloop.

The command call \forlistloop{\grabfromouterlist{\mycolumnlist}}{\myrowlist} will loop through the \myrowlist content, i.e. the row number here in the example.

This row number,say 8, is fed to \grabfromouterlist{\mycolumnlist}{8} then etc. Since \grabfromouterlist itself uses \grabfrominnerlist, this will loop through \mycolumnlist and use the number 8 effectively etc.

\documentclass{article}
\usepackage{etoolbox}

\newcounter{rowcounter}
\newcounter{columncounter}
\newcounter{innercounter}

\newcommand{\addwithcounting}[3]{%
  \stepcounter{#1}
  \listadd{#2}{#3}
}

\newcommand{\grabfromouterlist}[3][a]{%
  \setcounter{innercounter}{0}% Reset the inner counter
  \forlistloop{\grabfrominnerlist[#1]{#3}}{#2} \\  % use the 2nd argument which is fed from the outer loop actually and process the list given as 1st argument. 
}

\newcommand{\grabfrominnerlist}[3][a]{%
  \stepcounter{innercounter}%
  \ifnumless{\value{innercounter}}{\value{columncounter}}{%
  #1_{#2#3} & % typeset the matrix element with index of row and column number
  }{%
  #1_{#2#3}% Final column, do not add a & character
  }%
}


\usepackage{mathtools}

\begin{document}  

\def\mycolumnlist{}  
\def\myrowlist{}  

\forcsvlist{\addwithcounting{rowcounter}{\myrowlist}}{1,2,3,4,5,6,7,8,9}
\forcsvlist{\addwithcounting{columncounter}{\mycolumnlist}}{1,2,3,4,5,6,7,8}

$\begin{pmatrix}
  \forlistloop{\grabfromouterlist[b]{\mycolumnlist}}{\myrowlist} 
\end{pmatrix}$


$\begin{Bmatrix}
  \forlistloop{\grabfromouterlist{\mycolumnlist}}{\myrowlist} 
\end{Bmatrix}$

$\begin{Bmatrix}
  \forlistloop{\grabfromouterlist[\sum]{\mycolumnlist}}{\myrowlist} 
\end{Bmatrix}$


\end{document}

enter image description here

Please note the use of the optional first argument, which defaults to a. This information has to be given on the outermost left side, as first parameter.

7
  • To be able to work with, say, 20 columns, one would issue the instruction \setcounter{MaxMatrixCols}{20}.
    – Mico
    Jul 21 '15 at 15:33
  • @Mico: Yes, I know, but the original question was about etoolbox nested loops, so I did not pursue the matrix 'problem'. Thanks anyway
    – user31729
    Jul 21 '15 at 15:36
  • Hi, I tried this out and another question is if you have to change the a_{61}{1} dynamically to say b_{6}{1} dynamically. What kinds of changes needs to be done to the grabfrom outerlist and grabfrom inner list macros.I tried to input 3 variables to get outerloop (by changing the number of arguments allowed from 2 to 3) but have not been successful. Jul 21 '15 at 22:36
  • @sumantamukherjee: You're changing the question actually. I've no time right now, I will look later on
    – user31729
    Jul 22 '15 at 4:27
  • I am using the way that was shown by Dr Hupfer and I found that it works for all cases that I have till now except one case where I have to change the names dynamically which I have put in my comment. I will post that solution after I am able to get that working. Jul 22 '15 at 10:06
21

For example something like this:

\long\def\for#1in#2#3{\expandafter\def\csname b:\string#1\endcsname{#3}%
   \forinA#1#2,,}
\def\forinA#1#2,{\ifx,#2,\else
   \def#1{#2}\csname b:\string#1\endcsname \expandafter\forinA\expandafter#1\fi}

\for\i in{a, bc, d}
{%
   \for\j in{A, B, C}
   {%
      i=\i, j=\j;\par
   }
}
4
  • 1
    Welcome back! :-)
    – Mico
    Jul 21 '15 at 13:09
  • 2
    Is there a particular advantage to reinventing this wheel?
    – Raphael
    Jul 22 '15 at 11:37
  • 1
    @Raphael The particular advantage is: you can learn the TeX primitive language in this very simple case. If you know this language very well then you can do everything. But this is simply your choice. For example, it is much more simple to me to write down such four lines of code than to waste my time by finding where similar thing is done.
    – wipet
    Jul 23 '15 at 14:12
  • Fair enough. FWIW, I have found the opposite to be true (for me) when using TeX - LaTeX as a resource.
    – Raphael
    Jul 23 '15 at 14:21
12

Some ideas with expl3:

\documentclass{article}
\usepackage{amsmath}
\usepackage{xparse}

\ExplSyntaxOn

\NewDocumentCommand{\doublelist}{m+O{}mO{}m}
 {% #1 = first list, #2 = code to execute at the end of the inner cycle
  % #3 = second list, #4 = code to execute between elements in the inner cycle
  % #5 = two argument macro to which items are passed
  \clist_map_inline:nn { #1 }
   {
    \clist_map_inline:nn { #3 }
     {
      #5 { ##1 } { ####1 } #4
     }
    #2
   }
 }

\ExplSyntaxOff

\newcommand{\coeff}[2]{$a_{#1,#2}$}

\begin{document}

\doublelist{i,j,k,l}[\par]{u,v,w}[, ]{\coeff}

\end{document}

enter image description here

1
  • Just a note on style: I notice that most of your answers use only one space for successive indentation whereas l3styleguide still suggests two. Also, one-liners are supposedly supposed to be inlined with their braces (i.e. { #5 { ##1 } { ####1 } #4 }. Has l3 changed its recommendation? Jul 22 '15 at 16:27
8

As Christian Hupfer comment that \foreach could be easier but his answer is about etoolbox, I have taken the liberty of make a MWE with \foreach because in this case is enough:

MWE

\documentclass{article}
\usepackage{pgffor}
\pagestyle{empty}
\begin{document}
\foreach \ii in {1, 2, ...,4}{%
\foreach \jj in {a, b, ...,d}{%
\makebox[3em]{(\ii,\jj)}}\par}%
\end{document}
2
  • Hi, Is there a book where these things are available so that it is easier for me to refer than to ask and disturb you . Jul 22 '15 at 10:02
  • There are many. See here some books to start, but there are no book that can cover all the aspects of all any packages, so anyway use extensively texdoc <packagename> or CTAN documentation (and of course, if this is not enough, this site also ).
    – Fran
    Jul 22 '15 at 19:04
7

Here's a LuaLaTeX-based solution. Two examples of two-dimensional arrays constructed with Lua for loops are given. The first surrounds the i,j pairs with parentheses; the second embeds them in a LaTeX array enviroment -- note the use of & and \\ to separate cells within a row and across rows.

enter image description here

% !TEX TS-program = lualatex
\documentclass{article}
\usepackage{luacode} % for "luacode" environment

%% Define two Lua functions that work with two-dim. arrays
\begin{luacode}
function paren_array(m,n)
  for i = 1,m do
    for j = 1,n do
      tex.sprint("("..i..","..j..")  ")
    end
    tex.print("")  -- force a line break
  end
end

function subscript_array(ind,m,n)
  for i=1,m do
    for j=1,n do
      tex.sprint(ind.."_{"..i..j.."}")
      if j<n then 
        tex.sprint ( "&" )    -- cell separator (ampersand)
      else 
        tex.sprint( "\\\\" )  -- end of row (two backslashes)
      end
    end
  end
end
\end{luacode}

\begin{document}

%% call the first function
\directlua{ paren_array(9,9) }

\bigskip
%% call the second function from within a LaTeX "array" environment
$
A = \left[ \begin{array}{*{5}{c}}
       \directlua{ subscript_array( "a",5,5 ) } 
    \end{array} \right]
$
\end{document} 
1
  • Nice idea too...
    – user31729
    Jul 21 '15 at 17:47
1

This answer is essentially taken from Christian's post and modified a bit.

The basic idea of the post is how does the \forlistloop work. This is an idea from "functional programming" and that is precisely one of the reasons why I could not understand how the \forlistloop worked etoolbox . The basic idea if I might say is as follows.

\forlistloop{handler}{list}

This essentially means take the handler and apply this to every individual element of the list. This might appear obvious but it took me a lot of time to appreciate this change from the imperative style and hence I am posting a part of my code which I do not claim is my own but surely Christian's code modified a bit.

\documentclass{article}
\usepackage{etoolbox}
\usepackage{amsmath}

\newcommand{\addwithcounting}[3]{%
    \stepcounter{#1}
    \listadd{#2}{#3}
}

%\def\printItem#1#2#3{
%   \stepcounter{#1}
%   #2_#3
%}

\def\printItem#1#2#3{
        #1_{#2#3} \\
}

\def\createMatrix#1#2#3{%
    \getOuterLoop{#2}{#3}{#1}
}

\def\getOuterLoop#1#2#3{%
     % #1 row list #2 column list
    \forlistloop{\stepcounter{columncounter}\getInnerLoop{#3}{#1}}{#2}
}

\def\getInnerLoop#1#2#3{%
    \forlistloop{\stepcounter{rowcounter}\printItem{#1}{#3}}{#2}
}

\begin{document}    
    \newcounter{rowcounter}
    \newcounter{columncounter}
    \newcounter{innercounter}

    \setcounter{rowcounter}{0}
    \setcounter{columncounter}{0}

    \def\mycolumnlist{}  
    \def\myrowlist{}  

    \forcsvlist{\addwithcounting{rowcounter}{\myrowlist}}{r,\theta,z}
    \forcsvlist{\addwithcounting{columncounter}{\mycolumnlist}}{r,\theta,z}

    %
    \newcounter{itemcount}
    $
        %\getInnerLoop{itemcount}{\sigma}{\myrowlist}
        %\getOuterLoop{\myrowlist}{\mycolumnlist}
        \createMatrix{\sigma}{\myrowlist}{\mycolumnlist}
    $

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