# PGF/TikZ: How to store strings in array?

I'm trying to generate a lot of name badges. I'm wondering, is it possible to store the names as strings in one array, according to the PGF manual:

\def\myarray{{1,"two",2+1,"IV","cinq","sechs",sin(\i*5)*14}}


I tried this:

\def\names{{"Katie","Frank","Laura","Joe"}}


Without success, because it seems to store the whole string in \names variable, and if I write

\names[2]


The output will be

"Katie","Frank","Laura","Joe"


Laura


is what I want to write out.

So why is this not working? How could I use arrays? Does it require some special library?

-
Is this for using in a foreach loop? –  percusse Feb 19 '12 at 17:11
Here is an example that does not require quotes: \begin{tikzpicture} \def\mylist{Laura,Katie,Frank,Joe} \foreach[count=\xi] \x in \mylist \node[minimum width=1cm] (n\xi) at (\xi,\xi) {\x}; \end{tikzpicture}. The quotes are needed when you plugin your list into a macro and to protect the text from a math parser! –  percusse Feb 19 '12 at 17:19
No, i use it not in a foreach loop. Without foreach loop somehow it doesn't work for me, it gives back the whole string. Thanks! –  deeenes Feb 19 '12 at 21:04

This answer may be more generic than specifically relating to TikZ/PGF.

(La)TeX is a macro-based language, so it does not work as expected compared to other languages when dealing with "arrays". For example, while \names[2] should yield Laura where

\def\names{Katie, Frank, Laura, Joe}


(indexing from 0), (La)TeX considers [2] to have no connection to \names. As such, you're more likely to obtain the output Katie, Frank, Laura, Joe[2] - a concatenation of \names (as it is defined) and [2].

In order to allow for indexing like one typically would using arrays, you would need some other functionality. Here's an example of a list parser that works like you would expect arrays do:

\documentclass{article}
\usepackage{xparse}% http://ctan.org/pkg/xparse
\usepackage{etoolbox}% http://ctan.org/pkg/etoolbox
\newcounter{listtotal}\newcounter{listcntr}%
\NewDocumentCommand{\names}{o}{%
\setcounter{listtotal}{0}\setcounter{listcntr}{-1}%
\renewcommand*{\do}[1]{\stepcounter{listtotal}}%
\expandafter\docsvlist\expandafter{\namesarray}%
\IfNoValueTF{#1}
{\namesarray}% \names
{% \names[<index>]
\renewcommand*{\do}[1]{\stepcounter{listcntr}\ifnum\value{listcntr}=#1\relax##1\fi}%
\expandafter\docsvlist\expandafter{\namesarray}}%
}
\begin{document}
\newcommand{\namesarray}{Katie, Frank, Laura, Joe}%
\verb|\names:|\ \names \par
\verb|\names[2]:|\ \names[2] \par
\verb|\names[0]:|\ \names[0] \par
\verb|\names[5]:|\ \names[5]
\end{document}


The idea here is to store the names in an array \namesarray and then define a macro (or "function") that takes an optional argument. If no argument is supplied (i.e., you just use \names), then you print the entire \namesarray. If an argument is supplied (of the form \names[<index>]), parse the list sequentially to find that item that matches <index> and print it.

The list parser relies on etoolbox's \docsvlist and enumerator \do.

-
Wow, you implemented it very professionally! It works fine. I'm just adding one comment: i can get the values of the array with a counter, like this: \newcounter{i} \setcounter{i}{0} \names[\value{i}] \stepcounter{i} ...So it's perfect! –  deeenes Feb 19 '12 at 21:08
Thank you for the nice code and explanation! –  deeenes Feb 19 '12 at 21:16

To answer the specific question you are asking, here is a complete minimal example.

\documentclass{standalone}
\usepackage{pgfmath}
\begin{document}
\def\names{{"Katie","Frank","Laura","Joe"}}%
\pgfmathparse{\names[2]}\pgfmathresult
\end{document}


So, you need to use the pgfmath parser to do the job through \pgfmathparse and then use the result of the parsing with \pgfmathresult: in other words, you cannot call \names[2] directly.

Here is a more complete example with a \foreach loop:

\documentclass{standalone}
\usepackage{pgfmath,pgffor}
\begin{document}
\def\names{{"Katie","Frank","Laura","Joe"}}%
\foreach \i in {0,...,3} {%
Name \i: \pgfmathparse{\names[\i]}\pgfmathresult, }
\end{document}

-
So now it's clear for me, what i need to make it work like in the PGF manual. Thanks! –  deeenes Feb 19 '12 at 21:19
Your second snippet doesn't work for me. Gives an error: Undefined control sequence. \pgfkeys. After replacing \usepackage{pgfmath,pgffor} to \usepackage{tikz} it worked. –  user4035 Apr 23 '13 at 22:54
Where is this syntax documented? I searched the documentation and found nothing... –  Dror Mar 31 at 13:22

The arrayjob package has some more macros for using the data array.

\documentclass{article}
\usepackage{arrayjob}

\newarray\names

\begin{document}
\verb|\names(3):|\ \names(3) \par
\verb|\names(1):|\ \names(1) \par
\verb|\names(5):|\ \names(5)
\end{document}


-
This one also works nice, thank you! –  deeenes Feb 19 '12 at 21:13

You don't need arrays (but arrays are described in the pgf manual). Also you don't need numbers to "index" the arrays.

\documentclass{beamer}
\usepackage{tikz}
\pgfkeys{/English to German/Peter/.code=Peter,
/English to German/Mary/.code=Maria,
/German to English/Peter/.code=Peter,
/German to English/Maria/.code=Mary}

\pgfkeys{/English to German/Peter}, % -> Peter
\pgfkeys{/English to German/Mary}, % -> Maria
\pgfkeys{/German to English/Peter}, and % -> Peter, and
\pgfkeys{/German to English/Maria}. % -> Mary.
\end{document}

-
It's easy, and works good. If i understand good, with this solution, i can define only one list? –  deeenes Feb 19 '12 at 21:13
No, you can have several lists. I've changed my example to show this. –  Marc van Dongen Feb 20 '12 at 1:07