0

I am using a properties list and I would like to be able to create a command that produces the list of keys to be used to generate a for loop. I am currently using \prop_map_inline to generate all the keys but if I use this in the for loop it is interpreted as a single item and not a collection of several items.

This is an example code:

\documentclass{article}
\usepackage{ifthen}
\usepackage{xparse}

\ExplSyntaxOn \prop_new:N \g_persons_prop

% Create a new person
\NewDocumentCommand{\CreatePerson}{m} {
    \prop_gput:Nnn \g_persons_prop { #1 }
}

% Gets all persons
\NewDocumentCommand{\GetAllPersonKeys}{}{
    \prop_map_inline:Nn \g_persons_prop {
        ##1, 
    }
}

\ExplSyntaxOff

\CreatePerson{jd}{John Doe} \CreatePerson{ad}{Albert Dull} \CreatePerson{bu}{Ben Under}

\begin{document} I would like to have this: \makeatletter \begin{itemize} @for\sun:={jd, ad, bu}\do{\item We have person: \sun. } \end{itemize} \makeatother

But I get this instead:

\makeatletter
    \begin{itemize}
        \@for\sun:={\GetAllPersonKeys}\do{\item We have person: \sun. }
    \end{itemize}
 \makeatother   

\end{document}

Example

egreg
  • 1,121,712
  • How many arguments do you intend CreatePerson to take? – user202729 May 10 '22 at 14:59
  • What do you really want to do? Why not just prop_map_inline ... {We have person: ...}? – user202729 May 10 '22 at 15:01
  • If you want some keywords to learn yourself, there are 2 issues here • GetAllPersonKeys as implemented as not expandable, and • you didn't even try to expand it before executing @for, so no guarantee. – user202729 May 10 '22 at 15:03
  • I want to be able to use @for over the keys, in this case jd, ad, bu. I want this because I want to be able to do general loops in which I use the keys. I want to avoid having \ExplSyntaxOn on the main code (I am working on a class). The points you mention in your third comment are my issue. I do not know how to expand it such that it can be used. I tried googling but I could not find an answer I could extrapolate to this case. – gorkiana May 10 '22 at 15:14
  • TeX programming is hard, if you don't learn it properly you'll get full of surprises. I guess if you want you can start at package writing - Where do I start LaTeX programming? - TeX - LaTeX Stack Exchange. – user202729 May 10 '22 at 15:30
  • Back to this point, it looks like that \@for f-expand the argument. So you have to use something f-expandable, such as \use:e's \expanded emulation plus some other prop_map function that is hollow-star. Try it yourself, if \tl_show:f {\GetAllPersonKeys} shows the correct comma-separated result you know it's correct. – user202729 May 10 '22 at 15:32
  • Alternatively if you allow some interface change, change the interface to \GetAllPersonKeys \@for \sun :={\AllPersonKeysResult} \do {...} it would be much easier to implement. – user202729 May 10 '22 at 15:33
  • Thank you for your comments. I do not understand you last comment. What are you proposing? Something like \edef\AllPersonKeysResult{\GetAllPersonKeys}? I tried it and it also does not work. Coul you explain it more? – gorkiana May 10 '22 at 15:51
  • \GetAllPersonsKeys is not expandable so you can't use it there. You could define it so that it fills a suitable command, but on the whole you are only making your live difficult by missing expl3 with @for like this. Stick to one system. – Ulrike Fischer May 10 '22 at 16:12
  • Thanks @UlrikeFischer! Then what would be the alternative without using expl3? I mean, how can I replace the property lists? – gorkiana May 10 '22 at 16:23
  • Well expl3 is implemented using just TeX after all, so if you are good enough at TeX you can reimplement everything you want. I don't recommend it though – user202729 May 10 '22 at 16:44
  • I said that, there exists an implementation such that \GetAllPersonKeys \@for \sun :={\AllPersonKeysResult} \do {...} does what you want, but you need the initial \GetAllPersonKeys to be outside. If you're happy with that the answer would be simpler. – user202729 May 10 '22 at 16:49

1 Answers1

1

You can map over the keys in expl3 too:

\documentclass{article}
\usepackage{ifthen}
\usepackage{xparse}

\ExplSyntaxOn \prop_new:N \g_persons_prop

% Create a new person
\NewDocumentCommand{\CreatePerson}{m} {
    \prop_gput:Nnn \g_persons_prop { #1 }
}

\NewDocumentCommand{\MapAllPersonKeys}{m}{
    \prop_map_inline:Nn \g_persons_prop {
       #1
    }
}


\ExplSyntaxOff

\CreatePerson{jd}{John Doe} \CreatePerson{ad}{Albert Dull} \CreatePerson{bu}{Ben Under}

\begin{document} I would like to have this:

  \makeatletter
    \begin{itemize}
        \@for\sun:={jd, ad, bu}\do{\item We have person: \sun. }
    \end{itemize}
 \makeatother

  \begin{itemize}
       \MapAllPersonKeys{\item we have person: #1!}
  \end{itemize}


\end{document}

enter image description here

Ulrike Fischer
  • 327,261
  • Thanks a lot! This is quite magical. Do I understand correctly that it replaces #1 in the command definition by #1 when calling as you propose? – gorkiana May 10 '22 at 17:03