# How to define a command to feed the contents of a list into an \ifcase construct?

It's common to use an \ifcase construct to redefine a command depending on the value of a counter. The following example illustrates this:

\documentclass{article}
\usepackage{xcolor}
\usepackage{etoolbox}

\newcommand\sectioncolor{}

\renewcommand\sectioncolor{%
\ifcase\value{section} brown\or red\or blue\else olive\fi}
\pretocmd{\section}{\color{\sectioncolor}}{}{}

\begin{document}

\section{Section One}
\section{Section Two}
\section{Section Three}
\section{Section Four}

\end{document}


The above redefinition of \sectioncolor using \ifcase implies manually feeding the colors in the \ifcase construct. What I would like to achieve is to have a command, say \ColorList, having as argument a comma separated list of variable length containing the colors to be used, and then redefine \sectioncolor to use the colors of the list depending on the section counter. So for example, referring to my sample code, using

\ColorList{brown,red,blue,olive}


would be equivalent to

\renewcommand\sectioncolor{%
\ifcase\value{section} brown\or red\or blue\else olive\fi}


and

\ColorList{yellow,magenta,cyan,orange,blue}


would be equivalent to

\renewcommand\sectioncolor{%
\ifcase\value{section} yellow\or magenta\or cyan\or orange \else blue\fi}


but. of course, without having to manually feed the colors into the \ifcase. How can this be done?

This is similar to @egreg's solution and avoids \ifcase in favour of just cycling the list, but the coding is probably a bit simpler (unless you'be already loaded expl3 for other reasons)

\documentclass{article}
\usepackage{xcolor}
\def\ColorList#1{\def\xcolorlist{#1}}
\let\xsection\section
\def\section{\expandafter\xxcycle\xcolorlist,\xcolorlist\xsection}
\def\xxcycle#1,#2{%
\ifx\relax#1\relax\else
\color{#1}%
\ifx\xcolorlist#2\else
\xcycle#1,#2%
\fi
\fi}

\def\xcycle#1,#2\fi\fi#3\xcolorlist{\fi\fi\ColorList{#2#3#1}}

\ColorList{yellow,magenta,cyan,orange,blue,green!30,red!50!black}
%\ColorList{yellow}
%\ColorList{}

\begin{document}

\section{Title}
\section{Title}
\section{Title}
\section{Title}
\section{Title}
\section{Title}
\section{Title}
\section{Title}
\section{Title}

\end{document}

• I find that \ColorList{yellow} (ie, with only one member) fails. I don't know how important this is. Anyway, I have eked out a patch but I don't feel qualified to edit your answer. – Ahmed Musa Apr 28 '12 at 23:36
• @AhmedMusa thanks I fixed it (I hope) for {yellow} and {} edge cases. – David Carlisle Apr 29 '12 at 0:20

Since you are using etoolbox already, you can use \docsvlist and redefine \do appropriately.

\documentclass{article}
\usepackage{xcolor}% http://ctan.org/pkg/xcolor
\usepackage{etoolbox}% http://ctan.org/pkg/etoolbox

\newcounter{listitem}
\newcommand\sectioncolor{%
\setcounter{listitem}{-1}% At this point, section counter has not been incremented
\renewcommand*{\do}[1]{%
\stepcounter{listitem}% Increment list counter
\ifnum\value{listitem}=\value{section}\color{##1}\fi% Match list counter with section counter
}
\docsvlist{yellow,magenta,cyan,orange,blue,green!30,red!50!black}%
}
\pretocmd{\section}{\sectioncolor}{}{}

\begin{document}

\section{Section One}
\section{Section Two}
\section{Section Three}
\section{Section Four}
\section{Section Five}
\section{Section Six}
\section{Section Seven}

\end{document}

• Nice and clean, I was looking forward to this one while reading the other answers. – ienissei Apr 29 '12 at 7:37

This will cycle over the listed colors:

\documentclass[convert,border=2,varwidth]{standalone}
\usepackage{xcolor,xpatch,xparse}
\xpretocmd{\section}{\sectioncolor}{}{}

\ExplSyntaxOn
\NewDocumentCommand{\ColorList}{m}
{
\seq_gset_split:Nnn \g_gonzalo_colors_seq { , } { #1 }
}
\seq_new:N \g_gonzalo_colors_seq

\NewDocumentCommand{\sectioncolor}{ }
{
\seq_gpop_left:NN \g_gonzalo_colors_seq \l_tmpa_tl
\seq_gput_right:NV \g_gonzalo_colors_seq \l_tmpa_tl
\color { \l_tmpa_tl }
}
\ExplSyntaxOff

\ColorList{yellow,magenta,cyan,orange,blue,green!30,red!50!black}

\begin{document}

\section{Title}
\section{Title}
\section{Title}
\section{Title}
\section{Title}
\section{Title}
\section{Title}
\section{Title}
\section{Title}

\end{document}


At every call of \sectioncolor the color to use is popped from the top of the sequence and put back at the bottom.

• I know this is an old answer but this is what I found ;). Could you explain why you'd use a sequence here rather than a comma list? I was trying to do something similar with clists and I realised that I wasn't sure whether I should be using those or sequences. Is there somewhere this is explained? (I understand that a sequence could use something other than a comma, but for a case like this where it is a comma anyway, I'm not very clear.) – cfr Oct 11 '15 at 23:37
• @cfr clists are more for “user interface”; sequences are more efficient. – egreg Oct 11 '15 at 23:39
• Thanks. So I guess there is no reason I can't carry on with them, now I've started. (Given the general inefficiency of my code, I don't think I will notice any loss ;).) – cfr Oct 12 '15 at 1:00

There are probably a dozen standard methods for parsing comma-separated lists, but I don't know any of them, so here's my ad hoc solution (with a grain of salt :)

\makeatletter
\newcommand\@else@ifc{\noexpand\else}
\newcommand\@or@ifc{\noexpand\or}

\def\commalisttoifcase#1,%
{%
#1\@commalisttoifcase
}

\def\@commalisttoifcase#1,#2,%
{%
\ifx\empty#2\empty
\@else@ifc\unexpanded{#1}%
\expandafter\@gobble
\else
\@or@ifc\unexpanded{#1}%
\expandafter\@commalisttoifcase
\fi
#2,%
}
\newcommand\ColorList[1]
{%
\edef\next
{%
\noexpand\renewcommand\noexpand\sectioncolor{%
\noexpand\ifcase\noexpand\value{section}
\commalisttoifcase#1,,\noexpand\fi
}%
}
\next
}

\makeatother


Then

\ColorList{yellow,magenta,cyan,orange,blue}
\show\sectioncolor


gives

> \sectioncolor=\long macro:
->\ifcase \value {section} yellow\or magenta\or cyan\or orange\else blue\fi .

• The LaTeX kernel uses @for, @for\next:=\alist\do{...}... – Yiannis Lazarides Apr 28 '12 at 6:07
• @YiannisLazarides I know that much, but I'd have to look in the code to find out whether it's expandable :-) – Stephan Lehmke Apr 28 '12 at 6:34

Here is a simple solution using xstring. It does not do the proper error control (what happens if there are more sections than colors), but correctly processes the first and the last section:

\documentclass{article}
\usepackage{xstring}
\makeatletter
\def\ColorList#1{\gdef\@ColorList{#1}}
\def\sectioncolor{%
\StrCount{\@ColorList}{,}[\@tempa]% The length of the
\@tempcnta\@tempa\relax%                list
\ifnum\the\c@section<2\relax\StrBefore{\@ColorList}{,}% The
% special case of first section
\else\ifnum\c@section=\the\@tempcnta\relax % The special case of
% last section
\StrBehind[\the\@tempcnta]{\@ColorList}{,}%
\else  % The general case
\@tempcntb=\the\c@section\relax
\StrBetween[\the\@tempcntb,\the\c@section]{\@ColorList}{,}{,}%
\fi\fi
}
\makeatother
\begin{document}
\pagestyle{empty}
\ColorList{brown,red,blue,olive}

\noindent\sectioncolor{}

\section{AAAA}

\sectioncolor{}

\section{BBBB}

\sectioncolor{}

\section{CCCC}

\sectioncolor{}

\section{DDDD}

\sectioncolor{}

\end{document}


In case you need more control, here is another solution.

\documentclass{article}
\usepackage[dvipsnames]{xcolor}
\usepackage{ltxkeys}
\usepackage{multicol}
\makeatletter
% Keys:
\ltxkeys@declarekeys[GM]{bodystyle}[bdsty@]{%
cmd/body name/section/
\edef\bdsty@bodyname{\unexpanded{#1}}%
\ifltxkeys@dec\else
\ifblankTF{#1}{%
\@latexerr{Section body name can't be empty}\@ehd
}{%
\ifinsetTF{,#1,}{,chapter,section,subsection,paragraph,}{}{%
\@latexerr{Section body name not recognized}\@ehd
}%
}
\fi;
cmd/style list command//
\edef\bdsty@stylelistcommand{\unexpanded{#1}}%
\ifltxkeys@dec\else
\ifsingletokenFT{#1}{%
\@latexerr{Style command \detokenize{#1} isn't a single token}\@ehd
}{%
\ifescapedTF{#1}{%
\ifx#1\@undefined
\@latexerr{Style command \detokenize{#1} is undefined}\@ehd
\else
\ifx#1\@empty
\@latexerr{Style command \detokenize{#1} is empty}\@ehd
\fi
\fi
}{%
\@latexerr{Style command \detokenize{#1} isn't escaped}\@ehd
}%
}%
\fi;
cmd/repeated code//
\edef\bdsty@repeatedcode{\unexpanded{#1}};
cmd/exit code//
\csn@edef{bdsty@\bdsty@bodyname @exitcode}{\unexpanded{#1}};
}

% User commands:
% \newbodystyle[<keyval>]
\newcommand\newbodystyle[1][]{%
\ltxkeys@setkeys[GM]{bodystyle}{#1}%
\cptexpanded{%
\letcsntocsn{bodystyle@\bdsty@bodyname}{\bdsty@bodyname}%
\csn@def{\bdsty@bodyname}{%
\def\noexpand\n@wstylelist########1,########2\noexpand\newbodystyle{%
\expandcsonce\bdsty@repeatedcode{########1}%
\xdef\expandcsonce\bdsty@stylelistcommand{%
\unexpanded{\ifblankTF{####2}{}{\unexpanded{####2},}%
\unexpanded{####1}}%
}%
}%
\noexpand\xifinsetTF{,}{\noexpand\expandcsonce
\expandcsonce\bdsty@stylelistcommand}{%
\unexpanded{\expandafter\n@wstylelist}\expandcsonce
\bdsty@stylelistcommand\noexpand\newbodystyle
}{%
\unexpanded{\expandafter\n@wstylelist}\expandcsonce
\bdsty@stylelistcommand,\noexpand\newbodystyle
}%
\noexpand\usename{bodystyle@\bdsty@bodyname}%
}%
}%
}
% \restorebodystyle{<body name list>}
\newcommand*\restorebodystyle[1]{%
\cptdocommalist{#1}{%
\ifcsndefTF{bodystyle@##1}{%
\letcsntocsn{##1}{bodystyle@##1}%
\csname bdsty@##1@exitcode\endcsname
}{%
}%
}%
}
\makeatother

% Example document:
\begin{document}
% Fonts:
\def\usefontpallete{%
\def\say{Current style: {\tt\detokenize\expandafter{\currstyle}}\par}%
\def\sayb{\def\currstyle{normal font}\normalfont}%
\def\style{\def\temp####1{\def\currstyle{####1}####1}\temp}%
\def\sectionstylelist{\tt,\sf,\bf,\rm,\it,\mdseries}%
\def\subsectionstylelist{\sl,\sc,\upshape}%
}
% Colors:
\def\usecolorpallete{%
\def\say{Current color: {\tt\detokenize\expandafter{\currstyle}}\par}%
\def\sayb{\def\currstyle{normal color}\normalcolor}%
\def\style{\def\temp####1{\def\currstyle{####1}\color{####1}}\temp}%
\def\sectionstylelist{orange,blue,red,red!50!black,ForestGreen}%
\def\subsectionstylelist{olive,magenta,cyan}%
}
\parindent0pt
\begin{multicols}{2}
\section{Title}
Normal style, default style.

\usecolorpallete
% Let's ignore font pallete in the current run:
%\usefontpallete

\newbodystyle[
body name          = section,
style list command = \sectionstylelist,
repeated code      = \style,
% Code to execute when \restorebodystyle is called:
exit code          = \sayb
]
\newbodystyle[
body name          = subsection,
style list command = \subsectionstylelist,
repeated code      = \style,
exit code          = \sayb
]
% A style may also be defined for 'paragraph'.

\section{Title}
\say aaa
\section{Title}
\say bbb
% Higher order cycles (eg, subsection) are independent of lower order
% cycles (eg, section):
\subsection{Subtitle}
\say ccc
\subsection{Subtitle}
\say ddd
\subsection{Subtitle}
\say eee
\subsection{Subtitle}
\say fff
\subsection{Subtitle}
\say ggg
% Restore subsection to default style:
\restorebodystyle{subsection}
\subsection{Subtitle}
\say hhh
\section{Title}
\say iii
\section{Title}
\say jjj
\section{Title}
\say kkk
\restorebodystyle{section}
\section{Title}
\say lll
\section{Title}
\say mmm
\end{multicols}
\end{document}


Just for fun, here is a cyclic loop that won't bomb out:

\documentclass{article}
\usepackage{xcolor}
\usepackage{catoptions}
\makeatletter
\newif\ifcyclicstop
% \cyclicdo[<max loop run>]<callback><listcmd>
\robust@def*\cyclicdo{\cpt@testopt\@cyclicdo{10000}}
\robust@def\@cyclicdo[#1]#2#3{%
\cyclicstopfalse
\def\cyclicnr{0}%
\def\@cyclica##1,##2{%
\edef\cyclicnr{\the\numexpr\cyclicnr+1}%
\ifnumcmpTF\cyclicnr>#1{%
\@latexerr{Max loop number #1 exceeded by \string\cyclicdo}\@ehd
}{%
#2{##1}%
\ifboolTF{cyclicstop}{%
\begingroup
\def\@cyclica####1\cyclicdo{\endgroup}%
\let\@cyclicb\@cyclica
}{}%
\expandafter\ifcseqTF\cpt@car##2x\car@nil\cyclicdo{%
\@cyclica##1,\cyclicdo
}{%
\@cyclicb##1,##2\@cyclicb
}%
}%
}%
\def\@cyclicb##1,##2\@cyclicb##3\cyclicdo{\@cyclica##2##3##1,\cyclicdo}%
\ifcsemptyTF{#3}{}{\expandafter\@cyclica#3,\cyclicdo}%
}
\makeatother

% Example document:
\begin{document}
\def\colorlist{yellow,magenta,cyan,orange,blue,green!30,red!50!black}
%\def\colorlist{yellow}
%\def\colorlist{}
\def\do#1{%
% Do only 10 cycles:
\ifnum\cyclicnr>10\relax\cyclicstoptrue\fi
{\color{#1}Current: \tt\detokenize{#1}}\endgraf
}
\cyclicdo\do\colorlist
\end{document}


ConTeXt provides \defineconversion and \convertnumber commands which cycle through the list of elements (or applies a macro to the number). This is useful for things like footnote markers (\dagger, \star, etc.), but can be easily overloaded for other tasks as well.

\defineconversion
[colors]
[red,blue,green]