6

My end goal is to highlight certain nodes depending on their value, and there will be quite a few of them so I need there to be a conditional in a for loop. I've tried the following MWE, but it doesn't do what I expect.

Essentially, I need to check if an integer is in a list of integers, and draw a node based on that.

\documentclass{article}
\usepackage{tikz}

\begin{document}
\begin{tikzpicture}
\foreach \x in {10, 9,..., 0}
{
    \ifcase \x10
    \or5
         \node[] {\x};
    \fi
}
\end{tikzpicture}
\end{document}

Edit: Question reworded for clarity after accepting answer.

9
  • Use \ifnum\x=10 instead of \if \x10.
    – user194703
    Commented Sep 26, 2019 at 18:19
  • @Schrödinger'scat I will later be using an \ifcase statement, here I only used \if for simplicity. The \ifnum would need to be nested a bunch of times in my end goal, so I would like to avoid that.
    – gilbereth
    Commented Sep 26, 2019 at 18:20
  • An \ifcase doesn't do a comparison, it just takes a number. \ifcase\x\relax <case 0>\or <case 1>\or <case 2>\or... \else <other cases>\fi. Commented Sep 26, 2019 at 18:22
  • You can use \ifcase of course. What does this have to do with \ifnum vs. \if? See @PhelypeOleinik comment. \ifcase goes through the integers one by one, starting from 0.
    – user194703
    Commented Sep 26, 2019 at 18:23
  • @PhelypeOleinik, I've edited the question to make it clearer, I don't believe it's a duplicate because I need to check a bunch of cases.
    – gilbereth
    Commented Sep 26, 2019 at 18:23

2 Answers 2

5

\if I understand the question correctly, you want to check whether or not a number is equal to A, B, C etc. This can be done as follows.

\documentclass{article}
\usepackage{tikz}

\begin{document}
\begin{tikzpicture}
\foreach \X in {10, 9,..., 0}
{
\pgfmathtruncatemacro{\itest}{ifthenelse(\X==5||\X==7,1,0)}
    \ifnum\itest=1
         \node at (\X,0) {\X};
    \fi
}
\end{tikzpicture}
\end{document}

For more extensive applications I recommend the memberQ function, which may or may not become one day part of the pgf world. It tests if an integer is in a list of integers.

\documentclass{article}
\usepackage{tikz}

\makeatletter
\pgfmathdeclarefunction{memberQ}{2}{%
  \begingroup%
    \edef\pgfutil@tmpb{0}%
    \edef\pgfutil@tmpa{#2}%
    \expandafter\pgfmath@member@i#1\pgfmath@token@stop
    \edef\pgfmathresult{\pgfutil@tmpb}%
    \pgfmath@smuggleone\pgfmathresult%
  \endgroup}
\def\pgfmath@member@i#1{%
    \ifx\pgfmath@token@stop#1%
    \else
      \ifnum#1=\pgfutil@tmpa\relax%
      \gdef\pgfutil@tmpb{1}%
      %\typeout{#1=\pgfutil@tmpa}
      \fi%
      \expandafter\pgfmath@member@i
    \fi}    
\makeatother
\begin{document}
\begin{tikzpicture}
\foreach \X in {10, 9,..., 0}
{
\pgfmathtruncatemacro{\itest}{memberQ({1,4,8},\X)}
    \ifnum\itest=1
         \node at (\X,0) {\X};
    \fi
}
\end{tikzpicture}
\end{document}
2
  • Follow up for the memberQ function - it doesn't seem to work for multi digit integers. For example, if I have "10" in the list, \itest will evaluate to 1 when \X is 0 or 1 - but not when \X is 10. Is there any way to enable multi digit numbers to work?
    – gilbereth
    Commented Sep 27, 2019 at 13:41
  • never mind, I got rid of "\pgfutil@firstofone" in the function, and that fixed it. It seems that if the first number in your list is multiple digits, it will read it as those digits instead of as one integer.
    – gilbereth
    Commented Sep 27, 2019 at 14:13
6

\ifcase doesn't work like the switch statement in other languages, in which you choose what values have a branch of their own. The syntax of \ifcase is:

\ifcase<number>
    <case 0>
\or <case 1>
\or <case 2>
\or <as many as you want>
\else <other cases>
\fi

you can't skip a value. In your code you'd need:

\foreach \x in {10, 9,..., 0}
{
  \ifcase\x \relax
      % 0
  \or % 1
  \or % 2
  \or % 3
  \or % 4
  \or % 5
     \node[] {\x};
  \or % 6
  \or % 7
  \or % 8
  \or % 9
  \or % 10
  \else % other cases
  \fi
}

which is a handful. For a small number of exceptions you could use \ifnum:

\foreach \x in {10, 9,..., 0}
{
  \ifnum\x=5 \relax
     \node[] {\x};
  \else\ifnum\x=10 \relax
     % do things with \x=10
  \else
     % possibly more cases
  \fi\fi
}

which can become a mess, once you have more than a couple of cases.

My suggestion: \int_case:nnF. You can specify each case individually and a false branch in case no other is taken:

\documentclass{article}
\usepackage{tikz}
\usepackage{expl3}
\ExplSyntaxOn
\cs_new_eq:NN \IntCasennF \int_case:nnF
\ExplSyntaxOff
\begin{document}
\begin{tikzpicture}
\foreach \x in {10, 9,..., 0}
{
  \IntCasennF {\x}
    {
      {5}{\node[] {\x};}
      {10}{<Code for 10>}
    }
    {<Other cases>}
}
\end{tikzpicture}
\end{document}
2
  • Thanks, your answer was really informative, although I accepted Schrödinger's cat's as it was a bit cleaner for my use case.
    – gilbereth
    Commented Sep 26, 2019 at 18:47
  • @gilbereth No problem :-) Since you rephrased your question to "Check if number is in list of numbers", this might also be of interest to you. Commented Sep 26, 2019 at 18:53

You must log in to answer this question.

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