About
Shop
LaTeX
Software
Books
Gallery
News
Contact
Blog
Settings
Account
Latest news 2024-10-15: New blog post: Tales for Our Times Book Launch.


2.7.3 Iteration With etoolbox's Internal Lists

The previous section looked at iterating over a comma-separated list, but it may be that you need to first construct a list before iterating over it. This can be done efficiently via etoolbox's internal lists. These don't use a comma as a separator so it's useful for lists where items may potentially contain commas. For example, suppose I want to make a list called, say, \mylist, then I first need to define an empty list:

\newcommand*{\mylist}{}

An item can be added to the list using:

\listadd{list cs}{item}

where ⟨list cs⟩ is the command used to store the list (\mylist in the above example) and ⟨item⟩ is the item to add to the list. Note that the ⟨item⟩ doesn't get expanded and a blank item won't be added to the list. For example:

\listadd{\mylist}{Parrot}
\listadd{\mylist}{Parrot, Jr}

If the item needs to be expanded before being added to the list, you can use:

\listeadd{list cs}{item}

As with \listadd, a blank item won't be added to the list. For example:

\newcommand*{\Name}{Canary}
\listeadd{\mylist}{\Name}

There are also similar commands where you supply the name of the list macro without the leading backslash:

\listcsadd{list csname}{item}

(unexpanded item) and

\listcseadd{list csname}{item}

(expanded item). For example:

\renewcommand*{\Name}{Zebra}
\listcseadd{mylist}{\Name}
\listcsadd{mylist}{Arara}

These commands all use local assignments, so they're limited to the current scope. There are analogous commands that use global assignments:

\listgadd{list cs}{item}

(global version of \listadd)

\listxadd{list cs}{item}

(global version of \listeadd)

\listcsgadd{list csname}{item}

(global version of \listcsadd) and

\listcsxadd{list csname}{item}

(global version of \listcseadd).

You can test if an item is in a list using:

\ifinlist{item}{list cs}{true}{false}

(No expansion is performed on ⟨item⟩.) For example:

Parrot
\ifinlist{Parrot}{\mylist}{is}{isn't}
in the list.

If you want to test the expansion of an item, you can use:

\xifinlist{item}{list cs}{true}{false}

For example:

\newcommand*{\Name}{Parrot}%
\Name\␣\xifinlist{\Name}{\mylist}{is}{isn't} in the list.

There are also analogous commands where the list control sequence name (without the leading backslash) is supplied:

\ifinlistcs{item}{list csname}{true}{false}

for the non-expanded version and

\xifinlistcs{item}{list csname}{true}{false}

for the item expansion version.

Once you've added all your items to the list, you can iterate over the list using:

\dolistloop{list cs}

where ⟨list cs⟩ is the control sequence storing the list (\mylist in the above examples). If you prefer to supply the control sequence name without the leading backslash, you can use:

\dolistcsloop{list csname}

Both these commands use \do{item} at each iteration, in the same way as for \docsvlist described earlier. For example:

\newcommand*{mylist}{}%
\listadd{\mylist}{Parrot}%
\listadd{\mylist}{Canary}%
\listadd{\mylist}{Zebra}%
\listadd{\mylist}{Arara}%
\listadd{\mylist}{Duck}%
\renewcommand*{\do}[1]{#1. }%
\dolistloop{\mylist}

produces:

Parrot. Canary. Zebra. Arara. Duck.

Alternatively, you can provide your own handler instead of using \do:

\forlistloop{handler cs}{list cs}

where ⟨handler cs⟩ is the command to use on each iteration of the list and ⟨list cs⟩ is the list control sequence. If you prefer to supply the list control sequence name without the leading backslash you can use:

\forlistcsloop{handler cs}{list csname}

Exercise 4. Internal Lists

Create a document that loads the sample booklist.csv file or the books SQL table. Then create an internal list that contains a list of all the book titles, without repetition. For example, if a title has both a hardback and paperback edition only add that title once rather than twice.

To test the list, iterate through it and display each item of the list. (If you like, you can just use a paragraph break between items rather than using a tabular environment.) The result should look like:

The Adventures of Duck and Goose
The Return of Duck and Goose
More Fun with Duck and Goose
Duck and Goose on Holiday
My Friend is a Duck
Annotated Notes on the ‘Duck and Goose’ chronicles
‘Duck and Goose’ Cheat Sheet for Students
‘Duck and Goose’: an allegory for modern times? End of Image.


You can download or view the solution to this exercise.


This book is also available as A4 PDF or 12.8cm x 9.6cm PDF or paperback (ISBN 978-1-909440-07-4).

© 2015 Dickimaw Books. "Dickimaw", "Dickimaw Books" and the Dickimaw parrot logo are trademarks. The Dickimaw parrot was painted by Magdalene Pritchett.

Terms of Use Privacy Policy Cookies Site Map FAQs