10

I would like to use \foreach to replace the next code :

\def\x{0}
\edef\y{\x}     
\xdef\z{(b\y)}       

\def\x{1}
\edef\y{\x}
\xdef\w{\z(b\y)}     

\def\x{2}
\edef\y{\x}
\xdef\z{\w(b\y)}  

\def\x{3}
\edef\y{\x}
\xdef\w{\z(b\y)}     
\w 

The aim is to get this result : (b0)(b1)(b2)(b3) with a macro

I got the result with \toks but perhaps it's possible to avoid this.

\documentclass{article}
\usepackage{tikz}

\begin{document}

\makeatletter
\toksdef\toks@=0 %  ?
\toksdef\toks@@=1 % 
\xdef\tmp{}%

\foreach \x in {0,1,2,3}{%
    \toks@\expandafter{\x}%
    \toks@@\expandafter{\tmp}%
    \xdef\tmp{\the\toks@@(b\the\toks@)}%
 }
\makeatother 
\tmp
\end{document} 

I think this code is not nice. What is the better way to get the result without an extern package ?

Alain Matthes
  • 95,075

3 Answers3

11

Using a big package loop structure is really overkill for this, as a single \def is enough

\def\x#1{\ifnum\numexpr#1\relax>0 \x{#1-1}\fi(b\the\numexpr#1\relax)}

\typeout{\x{3}}

produces

(b0)(b1)(b2)(b3)
David Carlisle
  • 757,742
8

The LaTeX kernel provides \@for that doesn't work in groups like \foreach:

\def\tmp{}
\@for\next:=0,1,2,3\do{\edef\tmp{\tmp(b\next)}}

In your code there's no need for \toks:

\foreach \x in {0,1,2,3}{%
    \xdef\tmp{\tmp(b\x)}%
 }

would work as well.

However, if the items are "dangerous" in the sense that they don't survive \edef (like \textbf or other similar tokens), using token registers is necessary for avoiding complete expansion and your way is good. It's better to use \toks2 and not \toks1 for local assignments, so you should do

\toksdef\toks@@=2
egreg
  • 1,121,712
  • yes I know that but I would like to use \foreach because I used often \foreach and I like some options of this macro. – Alain Matthes Apr 07 '13 at 17:59
  • @AlainMatthes If you don't want to use an external package you don't have \foreach. – egreg Apr 07 '13 at 18:02
  • :) ! I wanted to say only pgffor and not another package. I load always tikz in my works also I can work with pggfor and pgfkeys. – Alain Matthes Apr 07 '13 at 18:20
7

If you are using pgfkeys and pgffor (which is internally used by the .list handler), you can simply use the .list handler.

If you only need the sequence (b0)(b…)b(3) typeset, you can set up one .code key and use that key with the .list handler. (→ do)

However, if you want to have an expandable macro, this macro has to be fixed (→ doo, equivalent to \foreach \x in {0,...,3}{\xdef\tmp{\tmp(b\x)}}) or you need more than one key (→ dooo, more flexible).

Code

\documentclass{article}
\usepackage{pgfkeys,pgffor}
\makeatletter
\pgfkeys{/alain/do/.code=(b#1)}
\pgfkeys{/alain/doo/.code=\edef\tmp{\tmp(b#1)}}
\pgfkeys{/alain/dooo ini/.code=\let\qrr@doo@temp\pgfutil@empty,
         /alain/dooo/.code=\edef\qrr@doo@temp{\qrr@doo@temp(b#1)},
         /alain/dooo set/.code=\let#1\qrr@doo@temp}
\makeatletter
\begin{document}
\pgfkeys{/alain/do/.list={0,...,3}}

\def\tmp{}
\pgfkeys{/alain/doo/.list={0,...,3}}
\tmp

\pgfkeys{/alain/.cd,
         dooo ini,
         dooo/.list={0,...,3},
         dooo set=\myTemp}
\myTemp
\end{document}
Qrrbrbirlbel
  • 119,821