[Tex/LaTex] PGF/TikZ: How to store strings in array

arraysloopstikz-pgf

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" 

instead

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?

Best Answer

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:

enter image description here

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

Related Question