1

(This is my first question here, sorry for any "side effects" of it...)

I'd like to implement that, depending on the value of \MyR (a number between 0 and 1, 1 excluded), the first/second/... item of a set would be chosen. In the MWE below, a set is realized in the format {item1\or item2\or item3 ...}. If, for example, a set has two elements: {item1\or item2} then, for values of \MyR below 0.5, item1 would be returned, and for values above 0.5, item2 is to be returned. From a set {item1\or item2\or item3}, 0.33 would yield item1 while 0.34 would lead to item2. Below I use \ifcase, and compute which of its branches should be returned.

Version (*) (see below, implementation via \newcommandFromSet) seems to work. Hovewer, the variants (**) and (***) (two attempts for \FromSet) fail when we uncomment the last (but one) line %\fpeval.... The success of (*) seems to justify the basic concept, but how could I cure the definition of \FromSet? Thank you!

(Link to @egreg's \CountToken.)

[A format {item1\SomeShortToken item2\SomeShortToken item3 ...} would be easy to type, and calculating the number of items would also be for user convenience.]

\documentclass{article}  %% MWE
\usepackage{xfp}

\def\finish{\finish} %% Frequency of token #1 (stored \def\CountToken[#1,#2]{% %% in counter #2) in what's \def\TestedToken{#1}% %% between \CountToken[#1,#2] \ifdefined#2#2=0 \else\newcount#2\fi %% and \finish. Code copied from \let\TotalOccurrence#2% %% https://tex.stackexchange.com \let\next\TestNext\next %% questions/525556/token- } %% counter-strange-behaviour- \long\def\TestNext#1{% %% of-math-mode (egreg's version) \def\CurrentToken{#1}% %% \ifx\CurrentToken\finish %% \let\next\relax %% \else %% \ifx\CurrentToken\TestedToken %% \advance\TotalOccurrence by 1 %% \fi %% \fi %% \next %% } %%

\newcommand{\MyR}{0.67} %% my "global variable".

\newcommand{\newcommandFromSet}[2]{\CountToken[\or,\cnti]#2\finish %% () \xdef#1{\ifcase\fpeval{floor(\MyR(1+\cnti))} #2\fi}} \newcommand{\FromSet}[1]{\CountToken[\or,\cnti]#1\finish %% () \ifcase\fpeval{floor(\MyR*(1+\cnti))} #1\fi} %\renewcommand{\FromSet}[1]{\newcommandFromSet{\MyTemp}{#1}\MyTemp} %% (*)

\begin{document} \newcommandFromSet{\MyText}{first\or second\or third} \newcommandFromSet{\MyNumber}{11\or 12\or 13} The \MyText\ number is \MyNumber, I repeat, \fpeval{1*\MyNumber}. %% everything seems to be good.

The \FromSet{first\or second\or third} number is %% this line seems to work. \FromSet{11\or 12\or 13}, I repeat, %% this line also seems to work. %\fpeval{1*\FromSet{\or 11\or 12\or 13}}. %% ! Extra \or. \TestedToken ->\or \end{document}

TFulop
  • 75
  • Hello and welcome. I didn't understand what you want to do or your problem. – AndréC Jul 18 '20 at 19:03
  • I hope the edited version explains the situation better. – TFulop Jul 18 '20 at 20:01
  • Are you *sure* you want to count \or tokens with code that exploits \ifcase? That's quite likely the source of your problem. I'm quite confident that the second version in the answer you refer to doesn't suffer from the problem. – egreg Jul 18 '20 at 20:05
  • The implementation via \or and \ifcase is not necessary (just one seemingly plausible way), and it does work in the form of \newcommandFromSet. Nevertheless, more generally, I would be satisfied with any \SomeShortToken – or, say, a semicolon – in a format {item1\SomeShortToken item2\SomeShortToken item3 ...}. The format itself I find user-friendly, and I would like LaTeX to calculate the number of items (rather than the user). – TFulop Jul 18 '20 at 20:16
  • @egreg if you refer to the expl3 version: For the users I have in mind, the syntax of expl3 would be somewhat intimidating, I'm afraid… (I mean, they would also take a look at the preamble.) – TFulop Jul 18 '20 at 20:22
  • @TFulop Explain it! :-) Wouldn't they be intimidated also by that cryptic code with \CountToken? – egreg Jul 18 '20 at 20:52
  • This would be used in teaching, and I would take this opportunity to advocate/encourage using LaTeX among my colleagues, who are much more beginners than me. (I'm a beginner for >20 years: a slowly evolving one.) I would like to give them confidence that they can master LaTeX. With that eye, the syntax of expl3 – TFulop Jul 18 '20 at 20:59
  • E.g., they still get accustomed to that, unlike in other programming languages (OK, TeX is not exactly a programming language), here, _, numbers, and other 'exotic' characters are not allowed in command names. Their eyes still need training to learn what syntax is TeX-ish and what is not. A \CountToken is more consistent with their level, I think. – TFulop Jul 18 '20 at 21:08

1 Answers1

2

You can't use \or in that context, I'm afraid. But the code can be made much simpler.

I'd prefer comma separated items, rather than separated by \or, so the \FromSet macro is fully expandable.

With \clist_count:n we can access expandably the number of items, so we can scale the variable by it; then truncate and add 1.

\documentclass{article}
\usepackage{xfp}

\ExplSyntaxOn \NewDocumentCommand{\newcommandFromSet}{O{\MyR}mm} { \cs_new:Npx #2 { \clist_item:nn { #3 } { \fp_eval:n { trunc(#1\clist_count:n { #3 },0) + 1 } } } } \NewExpandableDocumentCommand{\FromSet}{O{\MyR}m} { \clist_item:nn { #2 } { \fp_eval:n { trunc(#1\clist_count:n { #2 },0) + 1 } } } \ExplSyntaxOff

\newcommand{\MyR}{0.67} %% my "global variable". \newcommand{\MyS}{0.1} %% another "global variable".

\begin{document}

\newcommandFromSet{\MyText}{first,second,third} \newcommandFromSet{\MyNumber}{,11,12,13}

The \MyText\ number is \MyNumber, I repeat, \fpeval{1*\MyNumber}.

The \FromSet{first,second,third} number is \FromSet{11,12,13}, I repeat, \fpeval{1*\FromSet{11,12,13}}.

\newcommandFromSet[\MyS]{\MyTextA}{first,second,third} \newcommandFromSet[\MyS]{\MyNumberA}{11,12,13}

The \MyTextA\ number is \MyNumberA, I repeat, \fpeval{1*\MyNumberA}.

The \FromSet[\MyS]{first,second,third} number is \FromSet[\MyS]{11,12,13}, I repeat, \fpeval{1*\FromSet[\MyS]{11,12,13}}.

\end{document}

Note that you can use different variables; the default is \MyR.

enter image description here

egreg
  • 1,121,712
  • Thank you, @egreg. Unfortunately, my \MyR will be restricted between 0 and 1 so I need to determine the number of elements of a given set in order to calculate which item to return. – TFulop Jul 18 '20 at 20:30
  • 1
    @TFulop I misunderstood. With a change of syntax it's doable quite easily. I wouldn't use \or. – egreg Jul 18 '20 at 20:49
  • Thank you (as a newcomer, my upvote is not displayed)… I've also tried to modify your code to ; as the separator (I'm from a country with decimal comma), but failed. And | as the separator gave a funny result. What separators would be allowed? Or how about an \OR? – TFulop Jul 18 '20 at 21:19
  • @TFulop Sorry, but ; would make the macros not expandable. Just brace numbers that have a comma in them. – egreg Jul 18 '20 at 21:22
  • If I try \fpeval{1*\FromSet[\MyS]{{1,1},{1,2},{1,3}}}. as the last but one line, the output is surprising. – TFulop Jul 18 '20 at 21:29
  • @TFulop \fpeval doesn't accept a comma as the decimal separator. Sorry, but you can do nothing about it. Use \num from siunitx for displaying numbers and always use the decimal period for the input. – egreg Jul 18 '20 at 21:37
  • I see; only siunitx is such liberal with the decimal comma. We will cope with the decimal point and the braces (for text items containing a comma). Thank you! – TFulop Jul 18 '20 at 21:58