27

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?

  • Is this for using in a foreach loop? – percusse Feb 19 '12 at 17:11
  • 4
    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
25

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.

  • 1
    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
  • Is it possible to get the size of the array? (I would like to use it in a \forloop) – Zach Sep 8 '16 at 18:28
  • 1
    @Zach: You can use \sbox9=\hbox{\names} (processes \names but doesn't print it) which then allows you to use the listtotal counter that holds the number of items in the list. – Werner Sep 8 '16 at 18:46
42

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
  • 1
    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 '14 at 13:22
13

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

\documentclass{article}
\usepackage{arrayjob}

\newarray\names
\readarray{names}{Katie&Frank&Laura&Joe}

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

enter image description here

Note:
The arrays are 1 based (index starts at 1)

8

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. – user10274 Feb 20 '12 at 1:07
  • @user10247: please insert \begin{document} into your code. – Black Mild Sep 5 '18 at 8:41

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.