4

Using pgfkeys, suppose that I have a key whose value is a comma separated list:

\pgfkeys{/a list/.initial = {1,2,3}}

Question What is the correct way to iterate over this list using \foreach (from pgffor)?

The only way that I have found that works is to forcibly extract and expand the key value with something like:

\edef\alist{\pgfkeysvalueof{/a list}}
\foreach \a in \alist {A = \a\newline}% works!

This works but is ungainly as it shouldn't be necessary to extract the value of a key into a temporary variable in order to use it. My initial thought/hope was that something like

\foreach \a in \pgfkeysvalueof{/a list} {a = \a\newline}

would work, but this gives an error (! Argument of \pgfkeysvalueof has an extra }.)

Is there an "officially sanctioned" pgf approach for looping over a comma separated list that is the value of a pgf key? I initially got excited when I found the .list handler. It is not unlikely that .list does give a way of doing what I want but for the life of me I can't figure how to use it!

Bonus question Give an example showing what the .list handler does.

Here is full MWE:

\documentclass{article}
\usepackage{pgfkeys,pgffor}

\pgfkeys{/a list/.initial = {1,2,3}}

\begin{document}

    \edef\alist{\pgfkeysvalueof{/a list}}
    \foreach \a in \alist {A = \a\newline}% ugly, but works!

    %\foreach \a in \pgfkeysvalueof{/a list} {a = \a}% does not work

\end{document}
4

Here are two solutions:

\documentclass{article}
\usepackage{pgfkeys}
\usepackage{pgffor}
\pgfkeys{
  /list1/.initial = {1,2,3},
  %
  /list2/.store in=\mylisttwo,
  /list2={1,2,3},
}

\begin{document}

\pgfkeys{body loop/.code={A = #1\par},body loop/.list/.expanded=\pgfkeysvalueof{/list1}}

\pgfkeys{/list1={a,b,c}}
\pgfkeys{body loop/.code={A = #1\par},body loop/.list/.expanded=\pgfkeysvalueof{/list1}}

\foreach \b in \mylisttwo {B = \b\par}
\pgfkeys{/list2={a,b,c}}
\foreach \b in \mylisttwo {B = \b\par}

\end{document}

To simplify usage, I define a generic style apply to key:

\documentclass{article}
\usepackage{pgfkeys}
\usepackage{pgffor}
\pgfkeys{
  apply to key/.style n args={2}{@body loop/.code={#1},@body loop/.list/.expanded=\pgfkeysvalueof{#2}},
  /list1/.initial = {1,2,3},
}
\begin{document}
\pgfkeys{apply to key={AA = #1\par}{/list1}}
\pgfkeys{/list1={a,b,c}}
\pgfkeys{apply to key={AA = #1\par}{/list1}}
\end{document}
  • Thanks Paul! How does the list1 solution work when I change the value of list1? I tried \pgfkeys{/list1={a,b,c}}\pgfkeys{body loop} but this did not work . [Your list2 solution is similar to the \edef solution in the question and, like it, this approach suffers from the problem that it creates an external variable \mylisttwo outside of pgfkeys...I know that I am idiosyncratic, but I prefer to keep the data inside the pgfkeys...] – Andrew Feb 3 '17 at 7:59
  • @Andrew I updated my code to add examples. – Paul Gaborit Feb 3 '17 at 9:49
  • Thanks Paul. I'm afraid that this is less elegant than the solution that I posted. – Andrew Feb 5 '17 at 2:02
  • @Andrew My apply to key solution is generic (you can apply it on any key, list of values or simple value) and does not suffer from the \foreach problem (the body of \foreach is an implicit group). – Paul Gaborit Feb 5 '17 at 10:59
  • You're right, it is nice. Perhaps I didn't appreciate it enough. You also give a nice example of using .list. I am still surprised that there isn't a more direct way of doing this. – Andrew Feb 6 '17 at 2:57
4

Not sure if your application would permit a listofitems alternative solution.

\documentclass{article}
\usepackage{listofitems}
\begin{document}
\setsepchar{,}

\readlist*\alist{1,2,3}

\foreachitem\a\in\alist{A = \a\newline}
\end{document}

enter image description here

  • 1
    Thanks Steven. I didn't know about thew listofitems package. With pgffor, it is possible to do what I want using\def\alist{1,2,3}\foreach \a in \alist {...} but I really want to do this using pgfkeys. – Andrew Feb 3 '17 at 3:07
2

Here is a pgf-style answer along the lines of what I am looking for but it places the \foreach loop inside the pgfkeys definition rather than having the loop outside of the key structure:

\documentclass{article}
\usepackage{pgfkeys,pgffor}

\pgfkeys{/mykeys/.is family,/mykeys}
\newcommand\MyKey[1]{\pgfkeys{/mykeys, #1}}
\MyKey{list/.style={llist/.code={\foreach \a in {#1}{A=\a\newline}}}}
\parindent=0pt

\begin{document}

  \MyKey{list={1,2,3}}
  \MyKey{llist}

  \MyKey{list={a,b,c}}
  \MyKey{llist}

\end{document}

I'd prefer a solution that allows me to loop over the key value outside of the pgfkeys definition and that does not require a "helper" key, like llist above.

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.