# Test if the value of a counter belongs to a given list of values

This must be a LateX 101 question, so I ask for your kindness

I want to make a choice based on the value of a theorem counter.

I use the xifthen package (especially the \isin function, which tests if a first string is a part of a second string) and the following function:

\newcommand{\test}[2]{\ifthenelse{\isin{|#1|}{#2}}{Yes}{No}}


For example:

\test{17}{|15|17|19|} returns Yes

\test{18}{|15|17|19|} returns No

But how to replace the first argument of \test by the current value of a counter?

Or use package xstring, which has all manner of neat tests built in:

\documentclass{article}

\usepackage{xstring}

\newcounter{sausage}
\setcounter{sausage}{18}

\begin{document}

\IfSubStr{|17|18|19|}{|\arabic{sausage}|}{true}{false}
\IfSubStr{|17|15|19|}{|\arabic{sausage}|}{true}{false}

\end{document}

• \IfSubStr{17|118|19} {\arabic{sausage}}{true}{false} yields true, which does not to seem to match the OP's request. You should write something like \IfSubStr{|17|118|19|} {|\arabic{sausage}|}{true}{false} instead. – Andrew Swann Nov 9 '16 at 8:47
\documentclass{article}
\usepackage{xifthen}
\newcounter{mycounter}
\setcounter{mycounter}{17}
\newcommand{\test}[2]{\ifthenelse{\isin{|#1|}{#2}}{Yes}{No}}
\begin{document}
\test{17}{|15|17|19|} returns Yes

\test{18}{|15|17|19|} returns No

\edef\tmp{\themycounter}
\expandafter\test\expandafter{\tmp}{|15|17|19|} returns Yes
\end{document}


This approach can be directly incorporated into the macro:

\documentclass{article}
\usepackage{xifthen}
\newcounter{mycounter}
\setcounter{mycounter}{17}
\newcommand{\test}[2]{%
\edef\tmp{#1}%
\ifthenelse{\expandafter\isin\expandafter{\expandafter|\tmp|}{#2}}{Yes}{No}%
}
\begin{document}
\test{17}{|15|17|19|} returns Yes

\test{18}{|15|17|19|} returns No

\test{\themycounter}{|15|17|19|} returns Yes
\end{document}


And for a completely different approach, here I use the listofitems package to parse argument #2 using expanded argument |#1| as the separator. If I get more than 1 element in the resulting array list, then one may conclude that the separator was found in #2.

\documentclass{article}
\usepackage{listofitems}
\newcounter{mycounter}
\newcommand{\test}[2]{%
\edef\tmp{#1}%
\expandafter\setsepchar\expandafter{\expandafter{\expandafter|\tmp|}}%
\ifnum\tmparraylen>1\relax Yes\else No\fi%
}
\begin{document}
\test{17}{|15|17|19|} returns Yes

\test{18}{|15|17|19|} returns No

\setcounter{mycounter}{17}
\test{\themycounter}{|15|17|19|} returns Yes
\end{document}


You can use pdfTeX's \pdfmatch{<strA>}{<strB>} which returns 1 if <strA> is found in <strB>. Pattern matching with punctuation requires some care. This is expandable:

\documentclass{article}

\newcommand{\test}[2]{\ifnum\pdfmatch{[|]#1[|]}{#2}=1 Yes\else No\fi}

\begin{document}

\verb!\test{17}{|15|17|19|}! returns: \test{17}{|15|17|19|}

\verb!\test{18}{|15|17|19|}! returns: \test{18}{|15|17|19|}

\newcounter{test}

\setcounter{test}{17}%
\verb!\test{\thetest}{|15|17|19|}! returns: \test{\thetest}{|15|17|19|}

\setcounter{test}{18}%
\verb!\test{\thetest}{|15|17|19|}! returns: \test{\thetest}{|15|17|19|}

\end{document}


The above pattern matching for \thetest works because \thetest expands to \arabic{test} (by default). If this is not the case, you can use \arabic{test} directly.

You can use \int_case:nnF of expl3.

\documentclass{article}

\usepackage{xparse}

\ExplSyntaxOn
\NewDocumentCommand{\test}{m}
{
\int_case:nnF { #1 }
{
{15}{Yes}
{17}{Yes,~it's~17}
{19}{Yes,~but~it's~big}
}
{No}
}
\ExplSyntaxOff

\newcommand{\fifteen}{15}
\newcounter{test}

\begin{document}

\test{17}

\test{\fifteen}

\setcounter{test}{19}
\test{\value{test}}

\setcounter{test}{42}
\test{\value{test}}

\test{43}

\end{document}


If you just want to do a yes/no comparison with a list of integers, you can do

\documentclass{article}

\usepackage{xparse}

\ExplSyntaxOn
\NewDocumentCommand{\test}{m}
{
\bool_if:nTF
{
\int_compare_p:n { #1 = 15 }
||
\int_compare_p:n { #1 = 17 }
||
\int_compare_p:n { #1 = 19 }
}
{Yes}
{No}
}
\ExplSyntaxOff

\newcommand{\fifteen}{15}
\newcounter{test}

\begin{document}

\test{17}

\test{\fifteen}

\setcounter{test}{19}
\test{\value{test}}

\setcounter{test}{42}
\test{\value{test}}

\test{43}

\end{document}


An extended version with three possible choices. The first does not accept the second argument in the form of alternatives, but is fully expandable; the second and the third versions accept the second argument, but only the latter is fully expandable.

\documentclass{article}

\usepackage{xparse}

\ExplSyntaxOn
\DeclareExpandableDocumentCommand{\testA}{m}
{
\bool_if:nTF
{
\int_compare_p:n { #1 = 15 }
||
\int_compare_p:n { #1 = 17 }
||
\int_compare_p:n { #1 = 19 }
}
{Yes}
{No}
}

\NewDocumentCommand{\testB}{mm}
{
\seq_set_split:Nnn \l_tmpa_seq { | } { #2 }
\seq_if_in:NfTF \l_tmpa_seq { \int_eval:n { #1 } }
{Yes}
{No}
}
\cs_generate_variant:Nn \seq_if_in:NnTF { Nf }

\DeclareExpandableDocumentCommand{\testC}{mm}
{
\ferrard_test:fn { \int_eval:n { #1 } } { #2 }
}

\cs_new:Nn \ferrard_test:nn
{
\ferrard_test_aux:nw { #1 } #2 | \q_stop
}
\cs_new:Npn \ferrard_test_aux:nw #1 #2 | #3 \q_stop
{
\tl_if_empty:nTF { #2 }
{No}
{
\int_compare:nTF { #1 = #2 }
{Yes}
{ \ferrard_test_aux:nw { #1 } #3 | \q_stop }
}
}
\cs_generate_variant:Nn \ferrard_test:nn { f }
\ExplSyntaxOff

\newcommand{\fifteen}{15}
\newcounter{test}

\begin{document}

\section{Test A}

\testA{17}

\testA{\fifteen}

\setcounter{test}{19}
\testA{\value{test}}

\setcounter{test}{42}
\testA{\value{test}}

\testA{43}

\section{Test B}

\testB{17}{15|17|19}

\testB{\fifteen}{15|17|19}

\setcounter{test}{19}
\testB{\value{test}}{15|17|19}

\setcounter{test}{42}
\testB{\value{test}}{15|17|19}

\testB{43}{15|17|19}

\section{Test C}

\testC{17}{15|17|19}

\testC{\fifteen}{15|17|19}

\setcounter{test}{19}
\testC{\value{test}}{15|17|19}

\setcounter{test}{42}
\testC{\value{test}}{15|17|19}

\testC{43}{15|17|19}

\end{document}


A no package, easily extendable approach.

I used \numexpr only for allowing expressions in input. And I use \detokenize only for displaying input. Else, these e-TeX extensions are not needed.

\documentclass{article}

\makeatletter
% borrowed from xintkernel.sty
\long\def\dothis #1#2\orthat #3{\fi #1}%
\let\orthat \@firstofone
\makeatother

\newcommand*{\test}[1]{The test of \texttt{\detokenize{#1}} gives:
\ifnum\numexpr#1=15 \dothis{Yes (15)}\fi
\ifnum\numexpr#1=17 \dothis{Yes (17)}\fi
\ifnum\numexpr#1=19 \dothis{Yes (19)}\fi
\orthat{NO!}%
}%

\newcommand{\fifteen}{15}

\newcounter{mycounter}

\begin{document}

\test{17}

\test{\fifteen}

\setcounter{mycounter}{19}
\test{\value{mycounter}}

\setcounter{mycounter}{42}
\test{\value{mycounter}}

\test{43}

\test{11+4+4}

\end{document}


Here I do not handle presenting the set of allowed values in the form |15|17|19| but macros can be of course produced for that. And with , as separator, then this is ready-made (expandably) via xinttools utilities (or LaTeX3 of course).

In the \dothis/\orthat approach (copied over from xintkernel.sty) the conditions are tested and as soon as one is positive the corresponding \dothis code executes, and then all left-over tests are skipped. If all such tests fail, it is the \orthat code that executes. This (all the \ifnum tests ending in \orthat{FOO}) is expandable code, of course. Here I added to \test macro extra stuff to better display results in mwe.

If the question is only to test if given input is in given list then old-timers method of \if1\ifnum .... etc... allow to put together many \ifnum without complicated \expandafter or \fi\fi...\fi.

But here I saw other answers handling separate code outputs according to input so I did the same.