3

Here is a minimal example of what I want to accomplish:

I have defined a list, such as this:

\def\listA{1/a/A,   2/b/B,  3/c/C}

I am now able to successfully loop through this list using

\foreach \x/\i/\j in \listA

However I want to be able to pick up items from this list using index numbers.

For example, I want to be able to do something like this:

ASSIGN \x/\i/\j listA[1]
\x   [this would print 1]
\i   [this would print a]
\j   [this would print A]

ASSIGN \x/\i/\j listA[2]
\x   [this would print 2]
\i   [this would print b]
\j   [this would print B]

Can this be done? THANK YOU!

3 Answers 3

1

Since you are using pgffor, here is something that does what you seem to want:

\documentclass{article}
\usepackage{pgffor}
\begin{document}
\def\listA{1/a/A,2/b/B,3/c/C}
\newcommand{\Assign}[1]{\foreach [count=\nn] \myx/\myi/\myj in \listA
{\ifnum\nn=#1 
\xdef\x{\myx}
\xdef\i{\myi}
\xdef\j{\myj}
\fi}
}
\Assign{1}
\x
\Assign{2}
\i
\end{document}

1 b

However, I personally would refrain from going that way.

3
  • Thank you. Is there a better way of doing this? Why do you not recommend this approach? I want to make it clear that I am using the same list (very long list in reality) for two different purposes in the same document. It is used with "\foreach" for one purpose, but it also has to be used with indices for another purpose.
    – ijm
    Oct 12, 2018 at 23:29
  • @ijm I guess that there are better approaches, yes. My main concern is that here some macros like \x etc. get defined globally. Since \x is such a common name, I'd refrain from doing that. (No, there is no problem in using \x in a plot of a tikzpicture, say, but still.) Given that you say you want to use it for longer lists: are you aware of the pgfplotstable? To me it seems you could use it here together with \ReadOutElement from here (this is not the first macro of this sort on this site).
    – user121799
    Oct 13, 2018 at 0:24
  • Thank you. What I have is a list of 40 items, each of which has an image file (graph) associated with it. Then I want to create a figure with 40 subfigures - and these will span 5 pages, 8 subfigures per page. I can split figures over multiple pages with \ContinuedFloat. But then that prevents me from using \foreach to list all the image files and corresponding captions in the right sequence. So I created one list, and then kept track of just indices, rather than actual names. I just implemented the code that uses your approach, and it works great for this purpose! Thank you!
    – ijm
    Oct 13, 2018 at 1:10
1

Here is a proposal, without \x and so on, because grouping doesn't seem possible in order to avoid (like \foreach does) clobbering existing commands.

\documentclass{article}
\usepackage{xparse}

\ExplSyntaxOn

\NewDocumentCommand{\definelist}{mm}
 {
  \clist_clear_new:c { l_ijm_list_#1_clist }
  \clist_set:cn { l_ijm_list_#1_clist } { #2 }
 }

\NewDocumentCommand{\assign}{mmm}
 {% #1 = list name, #2 = template, #3 = item number
  \ijm_list_assign:nnn { #1 } { #2 } { #3 }
 }

\NewExpandableDocumentCommand{\get}{m}
 {
  \prop_item:Nn \l__ijm_list_assign_prop { #1 }
 }

\seq_new:N \l__ijm_list_template_seq
\seq_new:N \l__ijm_list_item_seq
\prop_new:N \l__ijm_list_assign_prop
\cs_generate_variant:Nn \seq_set_split:Nnn { Nnx }

\cs_new_protected:Nn \ijm_list_assign:nnn
 {
  \seq_set_split:Nnn \l__ijm_list_template_seq { / } { #2 }
  \seq_set_split:Nnx \l__ijm_list_item_seq { / }
   {
    \clist_item:cn { l_ijm_list_#1_clist } { #3 }
   }
  \prop_clear:N \l__ijm_list_assign_prop
  \seq_mapthread_function:NNN
    \l__ijm_list_template_seq
    \l__ijm_list_item_seq
    \__ijm_list_assign:nn
 }

\cs_new_protected:Nn \__ijm_list_assign:nn
 {
  \prop_put:Nnn \l__ijm_list_assign_prop { #1 } { #2 }
 }

\ExplSyntaxOff

\begin{document}

\definelist{listA}{1/a/A, 2/b/B, 3/c/C}

\assign{listA}{x/y/z}{1}

\get{x}\par
\get{y}\par
\get{z}\par

\assign{listA}{x/y/z}{2}

\get{x}\par
\get{y}\par
\get{z}\par

\end{document}

You define a list and then you can \assign letters (or, more generally, strings) to the items, see the example. An item is produced with \get{<letter>}.

enter image description here

A different approach. Lists are defined as before (but you can change the delimiter). Instead of assigning symbolic names, you can access items in “matrix” form, that is

\get{<item number>}[<subitem number>]{<list name>}

The second argument is optional; if omitted, the whole item is returned.

\documentclass{article}
\usepackage{xparse}

\ExplSyntaxOn

\NewDocumentCommand{\definelist}{O{/}mm}
 {% #1 = divider (optional), #2 = name, #3 = items
  \seq_clear_new:c { l_ijm_list_#2_seq }
  \seq_set_from_clist:Nn \l__ijm_list_tempa_seq { #3 }
  \seq_map_inline:Nn \l__ijm_list_tempa_seq
   {
    \seq_set_split:Nnn \l__ijm_list_tempb_seq { #1 } { ##1 }
    \tl_clear:N \l__ijm_list_tempa_tl
    \seq_map_inline:Nn \l__ijm_list_tempb_seq
     {
      \tl_put_right:Nn \l__ijm_list_tempa_tl { {####1} }
     }
    \seq_put_right:cV { l_ijm_list_#2_seq } \l__ijm_list_tempa_tl
   }
 }

\NewExpandableDocumentCommand{\get}{mom}
 {
  \IfNoValueTF { #2 }
   {
    \seq_item:cn { l_ijm_list_#3_seq } { #1 }
   }
   {
    \tl_item:fn { \seq_item:cn { l_ijm_list_#3_seq } { #1 } } { #2 }
   } 
 }

\seq_new:N \l__ijm_list_tempa_seq
\seq_new:N \l__ijm_list_tempb_seq
\tl_new:N \l__ijm_list_tempa_tl
\cs_generate_variant:Nn \tl_item:nn { f }

\ExplSyntaxOff

\begin{document}

\definelist{listA}{1/a/A, 2/b/B, 3/c/C}

\get{1}[1]{listA}\par
\get{1}[2]{listA}\par
\get{1}[3]{listA}\par
\get{2}[1]{listA}\par
\get{2}[2]{listA}\par
\get{2}[3]{listA}\par
\get{3}{listA}

\end{document}

enter image description here

1
\documentclass{article}
\usepackage{xinttools}

\newcommand{\Assign}{}% check macro name is free (if not LaTeX shall complain)

\makeatletter
\def\Assign #1#2/#3#4/#5#6[#7]{%
    \oodef\Assign@tmp
       {\xintNthElt{#7}{\xintCSVtoList{\csname \xintZapSpaces{#6}\endcsname}}}%
    \expandafter\Assign@aux\Assign@tmp /#1/#3/#5/%
}
\def\Assign@aux #1/#2/#3/#4/#5/#6/{%
    \oodef#4{\xintZapSpaces{#1}}% remove leading and trailing spaces
                                % from item. Maybe not desired?
                                % see how 2/ b / B is handled
    \oodef#5{\xintZapSpaces{#2}}%
    \oodef#6{\xintZapSpaces{#3}}%
}%
\makeatother

\def\listA{1/a/A,    2/ b / B ,  3/c/C}

\begin{document}

\ttfamily

\Assign \x/\i/\j listA[1]

\string\x\ is \meaning\x+++

\string\i\ is \meaning\i+++

\string\j\ is \meaning\j+++

\Assign \X/\I/\J listA[2]

\string\X\ is \meaning\X+++

\string\I\ is \meaning\I+++

\string\J\ is \meaning\J+++
\end{document}

Produces

enter image description here

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .