3

I have several commands, called \cata to \catd. Now I need a command which loops over a given, comma-separated list, and calls the respective command. My current approach is:

\documentclass[10pt,a4paper]{article}
\usepackage[latin1]{inputenc}
\usepackage{amsmath}
\usepackage{amsfonts}
\usepackage{amssymb}
\usepackage{graphicx}
\usepackage{tikz}
\newcommand{\cata}{Hello a\newline}
\newcommand{\catb}{Hello b\newline}
\newcommand{\catc}{Hello c\newline}
\newcommand{\catd}{Hello d\newline}
\newcommand{\cat}[1]{%
\expandafter\newcommand\csname cat#1\endcsname%
}
\newcommand{\loopover}[1]{
\foreach \i in {#1}{
    \cat\i}
}
\begin{document}

Hello World\\
\loopover{a, b, c, d}
\end{document}

My expected output would be:

Hello World
Hello a
Hello b
Hello c
Hello d

If I change \loopover{a,b,c,d} to \loopover{a,a,c}, I want to get this

Hello World
Hello a
Hello a
Hello c

Up till now I get the error LaTeX Error: Command \cata already defined., which makes sense. Is there another way to achieve my intention?
Edit: I would like to expand the commands afterwards, so the current case is maybe a bit misleading. I would like to get the command \cata called itself, and not rewrite it.

The final application looks like:

\documentclass[10pt,a4paper]{article}
\usepackage[latin1]{inputenc}
\usepackage{amsmath}
\usepackage{amsfonts}
\usepackage{amssymb}
\usepackage{graphicx}
\usepackage{tikz}
\usepackage{tocloft}
\newcommand{\lista}{List a}
\newcommand{\listb}{List b}
\newcommand{\listc}{List c}
\newcommand{\listd}{List d}
\newlistof{cata}{expa}{\lista}
\newlistof{catb}{expb}{\listb}
\newlistof{catc}{expc}{\listc}
\newlistof{catd}{expd}{\listd}
\newcommand{\cata}[1]{%
    \refstepcounter{cata}
    \par\noindent\textbf{cata \thecata. #1}
    \addcontentsline{expa}{cata}
    {\protect\numberline{\thechapter.\thecata}#1}\par
}
\newcommand{\catb}[1]{%
    \refstepcounter{catb}
    \par\noindent\textbf{catb \thecatb. #1}
    \addcontentsline{expb}{catb}
    {\protect\numberline{\thechapter.\thecatb}#1}\par
}
\newcommand{\catc}[1]{%
    \refstepcounter{catc}
    \par\noindent\textbf{catc \thecatc. #1}
    \addcontentsline{expc}{catc}
    {\protect\numberline{\thechapter.\thecatc}#1}\par
}
\newcommand{\catd}[1]{%
    \refstepcounter{catd}
    \par\noindent\textbf{catd \thecatd. #1}
    \addcontentsline{expd}{catd}
    {\protect\numberline{\thechapter.\thecatd}#1}\par
}

\newcommand{\cat}[2]{%
\expandafter\newcommand\csname cat#1\endcsname{#2}%
}
\newcommand{\loopover}[2]{
\foreach \i in {#1}{
    \cat\i{#2}}
}
\begin{document}
\tableofcontents
\newpage
\lista\newline
\listb\newline
\listc\newline
\listd\newline
\chapter{TestA}
\cat{a,b}{Test}
\end{document}

I would like to loop over the list {a,b} given to \cat, and call the respective command in order to add {Test} to this table of content.

3
  • Do \newcommand\loopover[2]{\foreach\x in {#1}{\csname cat\x\endcsname{#2}}, where's the problem?
    – egreg
    Apr 9, 2016 at 11:32
  • I get Undefined control sequence. \loopover{a,b}{Test}
    – arc_lupus
    Apr 9, 2016 at 11:38
  • 1
    The undefined control sequence is \thechapter, which is obvious as the class is article. Use book.
    – egreg
    Apr 9, 2016 at 11:46

2 Answers 2

3

It's not clear why redefining \cat<x> each time:

\documentclass[10pt,a4paper]{article}

\usepackage{tikz} % \foreach
\newcommand{\cata}{Hello a\newline}
\newcommand{\catb}{Hello b\newline}
\newcommand{\catc}{Hello c\newline}
\newcommand{\catd}{Hello d\newline}
\newcommand{\loopover}[1]{%
  \foreach \i in {#1}{\csname cat\i\endcsname}%
}
\begin{document}

\noindent
Hello World\\
\loopover{a, b, c, d}
\loopover{a, a, c}

\end{document}

enter image description here

A simple implementation with xparse:

\documentclass[10pt,a4paper]{article}

\usepackage{xparse}

\ExplSyntaxOn
\NewDocumentCommand{\loopover}{m}
 {
  \clist_map_inline:nn { #1 } { \use:c { cat ##1 } }
 }
\ExplSyntaxOff

\newcommand{\cata}{Hello a\newline}
\newcommand{\catb}{Hello b\newline}
\newcommand{\catc}{Hello c\newline}
\newcommand{\catd}{Hello d\newline}

\begin{document}

\noindent
Hello World\\
\loopover{a, b, c, d}
\loopover{a, a, c}

\end{document}

This has several advantages over \foreach: for instance it automatically trims spaces around the items in the comma separated list and it doesn't hide the loop cycles in a group.

Here \clist_map_inline:nn is the loop making function and \use:c is expl3 lingo for \csname...\endcsname.


Update

Your more complicated code falls within the same solution. Just define

 \newcommand{\loopover}[2]{%
   \foreach \x in {#1}{\csname cat\x\endcsname{#2}}%
 }

There is no issue with this: if \x is a, the \cata token is formed and it absorbs the argument {#2} as usual.

2
  • Thanks! But is it possible to combine it with numbers in commands (difficult, I know), such that \cata becomes \cat1?
    – arc_lupus
    Apr 9, 2016 at 11:55
  • 1
    @arc_lupus In \csname...\endcsname you can use whatever you want so long as it is a character.
    – egreg
    Apr 9, 2016 at 12:59
1

Not sure if your example is just that, an example for a much more complex use case. But as far as your question is concerned, you can use xparse and a description environment.

Output

enter image description here

Code

\documentclass{article}
\usepackage{enumitem}
\usepackage{xparse}

\setlist[description]{itemsep=.3\baselineskip, font=\normalfont}

\NewDocumentCommand\mylist{>{\SplitList{,}}m}
  {
    \begin{description}
      \ProcessList{#1}{ \insertl }
    \end{description}
  }
\newcommand\insertl[1]{\item[Hello] #1}

\begin{document}
\noindent 
Hello world \par

\mylist{
    a, b, c, d
}%

\end{document}
5
  • The commands will do something different later (ToC-commands), not only displaying Hello #1, thus I would prefer if I could call the command directly.
    – arc_lupus
    Apr 9, 2016 at 11:01
  • @arc_lupus You should definitely show your final use for the command in your question, because making answerers "guess" your actual use is not useful. :)
    – Alenanno
    Apr 9, 2016 at 11:02
  • @arc_lupus Correct me if I'm wrong, but you want to use the letters to choose which command to execute? If so, you should make sure this is clear in your question.
    – Alenanno
    Apr 9, 2016 at 11:07
  • Will fix it in five minutes.
    – arc_lupus
    Apr 9, 2016 at 11:14
  • Added, I hope that helps
    – arc_lupus
    Apr 9, 2016 at 11:25

You must log in to answer this question.

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