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.

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

  • Thanks! But is it possible to combine it with numbers in commands (difficult, I know), such that \cata becomes \cat1? – arc_lupus Apr 9 '16 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 '16 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}
  • 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 '16 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 '16 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 '16 at 11:07
  • Will fix it in five minutes. – arc_lupus Apr 9 '16 at 11:14
  • Added, I hope that helps – arc_lupus Apr 9 '16 at 11:25

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.