3

I'm trying to understand why the \mymap function in the following code does not produce any output when called with a variable in a for loop (see \myloop). It produces output when text is explicitly passed to it. See \myloopb. Sorry for the simple question, I wasn't able to understand explanations of the \if and \ifx statements on stackexchange and other places. If it matters I'm using pdflatex from MikTex on Windows.

\documentclass[12pt]{article}
\usepackage{pgffor}

% define variables
\def\vala{aa}
\def\valb{bb}

% this produces different output depending on #1
\newcommand{\mymap}[1]{
  \def\temparg{#1}
  \ifx\temparg\vala
  Condition 1 is true
  \fi
  \ifx\temparg\valb
  Condition 2 is true
  \fi
}

\newcommand{\myloop}{
  \foreach \myvar in {\vala,\valb}{
    % this does not produce any output
    \mymap{\myvar}
  }
}

\newcommand{\myloopb}{
    % this produces output
    \mymap{aa}
    \mymap{bb}
}

\begin{document}
\section{Using myloop does not produce output}
% no output
\myloop
\section{Using myloopb produces output}
% produces output
\myloopb
\end{document}
1
  • Your code has many additional spaces in your macro definitions, you should use % to remove the spaces caused by the line endings (see my answer, in which I did that).
    – Skillmon
    Commented Feb 25, 2021 at 7:25

2 Answers 2

7

The issue is expansion here. \ifx tests whether the two following macros (if macros are passed) have the same meaning. In the first case \temparg has the meaning macro:->\myvar, whereas \vala has the meaning macro:->aa and \valb is macro:->bb.

Your \myvar has macro:->\vala and macro:->\valb as meaning in your loop. If you expand it twice before \mymap takes its argument, you get the correct meaning of \temparg. You can trigger earlier expansion with \expandafter<tokA><tokB>, which will expand <tokB> before <tokA> is expanded. So inside your loop use \expandafter\expandafter\expandafter\mymap\expandafter\expandafter\expandafter{\myvar}.

If your input is always fine to be fully expanded (it is in your example), you could use \edef\temparg{#1} instead, which is much cleaner than the \expandafter-chain proposed above.

\documentclass[12pt]{article}
\usepackage{pgffor}

% define variables
\def\vala{aa}
\def\valb{bb}

% this produces different output depending on #1
\newcommand{\mymap}[1]{%
  \edef\temparg{#1}%
  \ifx\temparg\vala
  Condition 1 is true%
  \fi
  \ifx\temparg\valb
  Condition 2 is true%
  \fi
}

\newcommand{\myloop}{%
  \foreach \myvar in {\vala,\valb}{%
    % this does not produce any output
    \mymap{\myvar}%
  }%
}

\newcommand{\myloopb}{%
    % this produces output
    \mymap{aa}%
    \mymap{bb}%
}

\begin{document}
\section{Using myloop does not produce output}
% no output
\myloop
\section{Using myloopb produces output}
% produces output
\myloopb
\end{document}
2

You can define a general purpose string case comparison.

\documentclass[12pt]{article}
\usepackage{pgffor}

% a string comparison function
\ExplSyntaxOn

\NewExpandableDocumentCommand{\StringCaseTF}{mm+m+m}
 {% #1 = string input, #2 = cases,
  % #3 = code to execute after a match
  % #4 = code to execute after no match
  \str_case_e:nnTF { #1 } { #2 } { #3 } { #4 }
 }

\ExplSyntaxOff

% define variables (not with \def)
\newcommand\vala{aa}
\newcommand\valb{bb}

% this produces different output depending on #1
\newcommand{\mymap}[1]{%
  \StringCaseTF{#1}{
    {\vala}{Condition 1 is true}
    {\valb}{Condition 2 is true}
  }{\par There was a match!}{\par There was no match!}%
  \par
}

\newcommand{\myloop}{%
  \foreach \myvar in {\vala,\valb,x}{
    % this does not produce any output
    \mymap{\myvar}
  }
}

\begin{document}

\myloop

\end{document}

Load xparse if you don't have the most recent LaTeX kernel.

enter image description here

The third or fourth arguments to \StringCaseTF can be left empty, of course.

You must log in to answer this question.

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