# Placing many conditionals in a series

I frequently need to do something like this:

IF x < 1, DO a
ELSE IF x < 2, DO b
ELSE IF x < 3, DO c
ELSE, DO d


Using etoolbox, I end up nesting a lot of ifnumless, like this:

\ifnumless{x}{1}{a}{
\ifnumless{x}{2}{b}{
\ifnumless{x}{3}{c}{
d
}
}
}


Is there a simpler way to achieve this?

-
This thread might help: tex.stackexchange.com/questions/17676/… –  Paulo Cereda Nov 26 '11 at 1:34
Well, TeX (and eTeX) has no \elseif, \elif; and needs \fi for every \if. So usually we always write bad-looking code. –  Leo Liu Nov 26 '11 at 7:34

A kind of "switchcase" can be easily programmes:

\documentclass{article}
\makeatletter
\def\ifnumcase#1{%
\edef\elseif@{\string\elseif}\edef\endif@{\string\endif}%
\def\number@test{#1pt}\ifnumcase@i}
\def\ifnumcase@i#1{%
\def\ifnumcase@ii##1{%
\csname
@\ifdim\number@test#1pt first\else second\fi oftwo%
\endcsname{##1\gobto@endif}\ifnumcase@i}%
\edef\valeur@{\string#1}%
\csname
\ifx\valeur@\elseif@ idto@endif%
\else\ifx\valeur@\endif@ relax\else ifnumcase@ii\fi
\fi
\endcsname}
\def\idto@endif#1\endif{#1}
\def\gobto@endif#1\endif{}
\makeatother
\begin{document}
\ifnumcase{7.5}% <- number to test
{<1}{less than 1}
{<3}{less than 3}
{>5}{greater than 5}
% add other tests if needed
\elseif
between 3 and 5% all tests faild
\endif

\ifnumcase{3.14}% <- number to test
{<2}{less than 1}
{<3}{less than 3}
{<4}{less than 4}
{<10}{less than 10}
\endif
\end{document}


EDIT: an even more complete and expandable solution with =, <, >, <= or <= tests:

\documentclass{article}
\usepackage[T1]{fontenc}
\makeatletter
\def\elseif{\elseif}\def\endif{\endif}
\def\ifnumcase#1#2{%
\expandafter\ifx\expandafter\elseif\@car#2\@nil\expandafter\@firstoftwo
\else
\expandafter\ifx\expandafter\endif\@car#2\@nil\expandafter\expandafter\expandafter\@gobbletwo
\else\expandafter\expandafter\expandafter\@secondoftwo
\fi
\fi
\idto@endif
{\if@eqin#2=\@nil{\if@dimwitheq{#1}#2\@nil}{\ifdim#1pt#2pt }
\expandafter\@firstoftwo\else\expandafter\@secondoftwo\fi\exec@arg{\ifnumcase@i{#1}}%
}%
}
\def\ifnumcase@i#1#2{\ifnumcase{#1}}
\def\if@eqin#1=#2\@nil{%
\ifx\@empty#2\@empty\expandafter\@secondoftwo
\else
\ifx\@empty#1\@empty\expandafter\expandafter\expandafter\@secondoftwo
\else\expandafter\expandafter\expandafter\@firstoftwo
\fi
\fi}
\def\if@dimwitheq#1#2=#3\@nil{\unless\ifdim#1pt\if<#2>\else<\fi#3pt }
\def\exec@arg#1#2\endif{#1}
\def\idto@endif#1\endif{#1}
\def\gobto@endif#1\endif{}
\makeatother
\begin{document}
\ifnumcase{3}
{<=1}{lt or equal 1}
{>=3}{gt or equal 3}
\elseif
beteween 1 and 3
\endif

\ifnumcase{4}% <- number to test
{<=1}{less or equal 1}
{<=3}{less or equal 3}
{=4}{equal 4}
{>=5}{greater or equal 5}
% add other tests if needed
\elseif
between 3 and 5% all tests faild
\endif

\edef\foo{\ifnumcase{5}% <- number to test
{<=1}{less or equal 1}
{<=3}{less or equal 3}
{=4}{equal 4}
{>=5}{greater or equal 5}
% add other tests if needed
\elseif
between 3 and 5% all tests faild
\endif}\meaning\foo

\ifnumcase{3.14}% <- number to test
{<2}{less than 1}
{<3}{less than 3}
{<4}{less than 4}
{<10}{less than 10}
\endif
\end{document}

-
What of \def\x{} \edef\x{% \ifsomecase\ifx\x \y{equal to \string\y} \z{equal to \string\z} % add possible other tests \elseif equal to none% \endif } \edef\x{% \ifsomecase\ifnum{2.1} {<=2}{equal or less than 2} {>=4}{equal or greater than 4} % add possible other tests \elseif equal to none% \endif } –  Ahmed Musa Nov 26 '11 at 21:39
"village" wanted to compare numbers... –  unbonpetit Nov 26 '11 at 22:13
But you've already exceeded what he wanted. We're now dealing with the more interesting exercises. :) Actually, adding \ifx, \ifstrcmp, etc. is routine. \def\elseif{\elseif} is like LaTeX3 quark. Use with care. –  Ahmed Musa Nov 26 '11 at 22:23
I don't think I have exceeded what he wants. After all, I have implemented tests on numbers. For sure, expandibility is probably a funny feature he didn't ask. I do not know what is a latex3 quark. Where in my code do you think I am careless? –  unbonpetit Nov 26 '11 at 22:48

Depending on who else needs to use the code, would lualatex work?

\documentclass{article}
\begin{document}
\directlua{
x=1.5
}
\directlua{
if x<1 then
tex.print('a')
elseif x<2 then
tex.print('b')
elseif x<3 then
tex.print('c')
else
tex.print('d')
end
}
\end{document}

-
I do not think LuaTeX will fit my needs well, as I always work with Unicode text. –  Village Nov 26 '11 at 3:17
@Village: Huh? Luatex works perfectly well with unicode. –  Aditya Nov 26 '11 at 6:56
I thought that LuaTeX uses unicode by design... –  qubyte Nov 26 '11 at 10:12

If you have it only to compare with integers then it is easy:

\documentclass{minimal}
\def\getInteger#1{\expandafter\stripDecimals#1..!!}
\def\stripDecimals#1.#2.#3!!{\ifx\relax#1\relax0\else#1\fi}

\def\x{\getInteger{0.5}}
\begin{document}

\ifcase\x   % 0
lt 1\or    % 1
lt 2\or    % 2
lt 3       % 3
\else gt 3  % else
\fi

\end{document}

-

Best Practices ? Question not specific enough, this depends of the engine, then you want to use TeX, LaTeX or LuaTeX etc. You want a concise code or fast code?

With TeX something like the code below is possible (there is other possibilities for example without \ifdim

\documentclass[11pt]{scrartcl}
\begin{document}
\def\x{1.5}

\ifdim \x pt< 1pt a
\else
\ifdim \x pt < 2 pt b
\else
\ifdim \x pt < 3pt c
\else  d
\fi
\fi
\fi
\end{document}

-

An expandable and more complete 'switch' solution is:

\documentclass{article}
\makeatletter
\def\identoendif#1\endif{#1}
\def\oneoftoendif#1#2\endif{#1}
\def\gobbletoendif#1\endif{}
\newcommand*\ifstrsame[2]{%
\@nameuse{@\ifnum\pdfstrcmp{\detokenize{#1}}%
{\detokenize{#2}}=0first\else second\fi oftwo}%
}
\def\dimexpr@i#1{#1\dimexpr}
\def\ifnumcase#1{%
\ifstrsame{#1}\elseif\gobbletoendif{%
\ifstrsame{#1}\endif\@gobble\ifnumcase@i
}{#1}%
}
\def\ifnumcase@i#1#2{%
\ifstrsame{#2}\elseif\identoendif{%
\ifstrsame{#2}\endif{}{%
\ifdim\dimexpr#1pt\relax\dimexpr@i#2pt\relax
\expandafter\@firstoftwo\else\expandafter\@secondoftwo\fi
{\oneoftoendif}{\ifnumcase@ii{#1}}%
}%
}%
}
\def\ifnumcase@ii#1#2#3{\ifnumcase@i{#1}{#3}}
\makeatother

%% Examples:
\edef\x{%
\ifnumcase{6}% <- number to test
{<1}{less than 1}
{<3}{less than 3}
{>5}{greater than 5}
% add other tests if needed
\elseif
between 3 and 5% all tests failed
\endif
}
\show\x -> greater than 5

\edef\x{%
\ifnumcase{3.14}% <- number to test
{<2}{less than 1}
{<3}{less than 3}
{<4}{less than 4}
{<10}{less than 10}
\endif
}
\show\x -> less than 4

\edef\x{%
\ifnumcase{314}% <- number to test
{<2}{less than 1}
{<3}{less than 3}
{<4}{less than 4}
{<10}{less than 10}
\endif
}
\show\x -> empty

\begin{document}
% Nothing to do:
\ifnumcase\elseif\endif
\ifnumcase{3}\elseif\endif
\ifnumcase\endif
\ifnumcase{3}\endif
\end{document}


unbonpetit's latest solution fails for

\ifnumcasse{3}
{=<1}{lt or equal 1}
{=>3}{gt or equal 3}
\elseif
beteween 1 and 3
\endif


and

\def\gobto@endif#1\endif{}


is redundant.

A more general solution is

\makeatletter
\def\elseif{\@gobble\elseif}
\def\endif{\@gobble\endif}
\def\swap#1#2{#2#1}
\def\ifstrsame#1#2{%
\ifnum\pdfstrcmp{\detokenize{#1}}{\detokenize{#2}}=\z@
\expandafter\@firstoftwo\else\expandafter\@secondoftwo\fi
}
\def\ifstrnull#1{%
\ifnum\pdfstrcmp{\detokenize{#1}}{}=\z@
\expandafter\@firstoftwo\else\expandafter\@secondoftwo\fi
}
\def\ifcmdeq#1#2{%
\ifx#1#2\endif\expandafter\@firstoftwo\else\expandafter\@secondoftwo\fi
}
\def\if@eqin#1=#2\@nil{%
\ifstrnull{#2}\@secondoftwo{\ifstrnull{#1}\@secondoftwo\@firstoftwo}%
}
\def\if@dimwitheq#1#2=#3\@nil{\unless\ifdim#1pt\if<#2>\else<\fi#3pt }
\def\docasecallback#1#2\endif{#1}
\def\doelsepart#1\endif{#1}
\def\ifnumcase#1#2{%
\expandafter\ifcmdeq\@car#2\@nil\elseif\@firstoftwo{%
\expandafter\ifcmdeq\@car#2\@nil\endif\@gobbletwo\@secondoftwo
}%
\doelsepart{%
\expandafter\expandafter\expandafter
\if@eqin\checkcomparators#2\@nil=\@nil{%
\expandafter\expandafter\expandafter\swap
\expandafter\expandafter\expandafter
{\checkcomparators#2\@nil}{\if@dimwitheq{#1}}\@nil
}{%
\ifdim#1pt#2pt %
}
\expandafter\@firstoftwo\else\expandafter\@secondoftwo\fi
\docasecallback{\ifnumcase@i{#1}}%
}%
}
\def\ifnumcase@i#1#2{\ifnumcase{#1}}
\def\checkcomparators#1#2#3\@nil{%
\romannumeral
\ifstrsame{#1}={\ifstrsame{#2}<{0<=#3}{\ifstrsame{#2}>{0>=#3}{0 #1#2#3}}%
}{0 #1#2#3}%
}
\makeatother

-
I do not find your little game funny. Ok, you win, you proove that you are much better than me and your solution are much more "general". Bye. –  unbonpetit Nov 27 '11 at 12:11
@unbonpetit Oh, I thought it was just another online game. Nothing to prove and nothing has been proved! Sorry. Bye, bye. –  Ahmed Musa Nov 27 '11 at 17:03
An online game??? Is it a game for you to give "better" or "more general" solutions than me? To say that my code "fails", that it contains "redundant" parts? For sure, it is a very easy to find a case in which a code does not work. It is probably funny to suggest that I am not careful enough with "quarks". Let me say that I answered the question because I just wanted to help "Village". Nothing esle. I was not looking for someone to correct me. And I was not looking for someone to compete with. You misunderstood my motivation! –  unbonpetit Nov 27 '11 at 18:29

Here's a solution to the problem of some elseif equivalent that is undoubtedly inefficient and probably encompasses numerous bad practices (including using the archaic ifthen package and using \else as a delimiter), but is very short and seems to work.

\RequirePackage{ifthen}
\def\fifi\relax
\newcommand{\ifif}{}             % I have no idea why this line is needed.
\long\def\ifif#1#2\else#3\fifi{\ifthenelse{#1}{#2}{#3\fifi}}


A usage example (which makes a lot more sense when you use SageTeX):

\documentclass{article}
\usepackage{mathtools}
\DeclarePairedDelimiter\floor{\lfloor}{\rfloor}

\RequirePackage{ifthen}
\def\fifi\relax
\newcommand{\ifif}{}
\long\def\ifif#1#2\else#3\fifi{\ifthenelse{#1}{#2}{#3\fifi}}

\let \oldmbox=\mbox
\renewcommand{\mbox}[1]{%
\ifif{\equal{floorHalfS}{#1}}%
\floor*{\tfrac{1}{2}s}%
\else\ifif{\equal{alphaS}{#1}}%
\alpha(s)%
\else\ifif{\equal{lprime}{#1}}%
\ell'%
\else\ifif{\equal{tprime}{#1}}%
t'%
\else\ifif{\equal{qprime}{#1}}%
q'%
\else\ifif{\equal{ell}{#1}}%
\ell%
\else\ifif{\equal{kprime}{#1}}%
k'%
\else%
\oldmbox{#1}%
\fifi%
}

\begin{document}

$\frac{\sqrt{\mbox{floorHalfS}^2 + 2\mbox{ell}}}{3\mbox{alphaS}}$

\end{document}


The result:

-