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.

gilbereth
  • 125
  • Use \ifnum\x=10 instead of \if \x10. –  Sep 26 '19 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 Sep 26 '19 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. – Phelype Oleinik Sep 26 '19 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. –  Sep 26 '19 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 Sep 26 '19 at 18:23
  • @gilbereth Well, now that you edited the problem is different :-) – Phelype Oleinik Sep 26 '19 at 18:24
  • Essentially what I need is: I will be drawing 10 (or more) nodes. I will be coloring some of them, the rest will be no fill. I need a way to check if the current iteration of the loop is an element that should be highlighted or not. – gilbereth Sep 26 '19 at 18:27
  • you are using \ifcase wrong. – Ulrike Fischer Sep 26 '19 at 18:28
  • @UlrikeFischer What is the correct usage, if you don't mind? I've found limited docs on it. Or is there a different construct I should use for my use case? – gilbereth Sep 26 '19 at 18:30

2 Answers2

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}
  • 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 Sep 26 '19 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. – Phelype Oleinik Sep 26 '19 at 18:53
4

\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}
gilbereth
  • 125
  • 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 Sep 27 '19 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 Sep 27 '19 at 14:13