3

I am trying to adapt this example How to iterate over a comma separated list? as my base. Except, rather than display all values, I actually want to iterate through all the values and only return / display the largest one.

The list of numbers I actually want to pass to a custom function will actually be glossaries labels. I have tested it and I can insert \gls{label} into a command like \clist_map_inline:nn { #1 } {\glsentryname{##1} } This works right away to display a list of my expanded values (which are actually numbers) so I am not worried about this part.

I haven't been able to figure out yet:

  1. How can I stop this function from typsetting the text, but rather allow me to iterate through the list update a variable only displaying the final value?

    • For example at the start of the loop I would set a dummy value such as -100000
    • and the comparison would compare ##1 iteratively with the dummy variable.
    • With a function call such as a call to my macro \pickGE included below I would then return and update the value if the value in the list is greater than the dummy.
  2. What approach would be appropriate to setup a dummmy variable that can be updated in this context

  3. How would I finally report this final selected value.
    • I would like to wrap this final value in a \num[scientific-notation = fixed, fixed-exponent = 0, group-digits=false]{} call.

The complete MWE I want to insert

\documentclass{article}
\usepackage{fp}
\usepackage{siunitx}
\usepackage{xparse}
\ExplSyntaxOn

\NewDocumentCommand{\findLargest}{ m }
 {
  \begin{enumerate}
  \clist_map_inline:nn { #1 } { \item \fbox{##1} }
  \end{enumerate}
 }

\ExplSyntaxOff

\newcommand{\pickGE}[2]{%
    \ifboolexpr{test {\ifdimgreater{{#1} pt}{{#2} pt}}}%
    {%
        \FPeval{result}{{#1}}%
    }% true
    {%
        \FPeval{result}{{#2}}%
    }% false
}


\begin{document}

\findLargest{1, 2 ,3 6, 3,1}

\end{document}

Limitations

  • I am committed to using XeLaTeX
  • I may be misremembering but I also have a vague recollection that siunitx had something to do this directly...
  • I am happy to use any other package or approach much like the one employed here (that I wasn't able to make work with my glossaries labels Iterating through comma-separated arguments
  • I am not limited to only comma separated lists but based on the shear volume of questions this looked like a good way to go.
6

Use the max function provided by expl3 in the fp module:

\documentclass{article}
\usepackage{xparse}
\ExplSyntaxOn

\NewDocumentCommand{\findLargest}{ om }
 {
  \IfNoValueTF{#1}
   {% separator is a comma, directly use \fp_eval:n { max ( #2 ) }
    \engbird_compute_max:n { #2 }
   }
   {% we need to pass the separator
    \engbird_find_largest:nn { #1 } { #2 }
   }
 }

\seq_new:N \l_engbird_largest_seq
\tl_new:N \l_engbird_largest_tl

\cs_new_protected:Npn \engbird_find_largest:nn #1 #2
 {
  % split the input at the stated separator
  \seq_set_split:Nnn \l_engbird_largest_seq { #1 } { #2 }
  % build a comma separated list
  \tl_set:Nx \l_engbird_largest_tl { \seq_use:Nn \l_engbird_largest_seq {,} }
  % compute the max
  \engbird_compute_max:V \l_engbird_largest_tl
 }
% syntactic sugar
\cs_new:Npn \engbird_compute_max:n #1
 {
  \fp_eval:n { max (#1) }
 }
\cs_generate_variant:Nn \engbird_compute_max:n { V }

\ExplSyntaxOff

\begin{document}

\findLargest{1, 2 ,3, 6, 3,1}

\findLargest[;]{ 1.5 ; sqrt(2) ; pi/2 }

\end{document}

enter image description here

If you want to use \num and you don't need different separators, here's a way, that also allows to override the options passed by default to \num:

\documentclass{article}
\usepackage{xparse}
\usepackage{siunitx}
\ExplSyntaxOn

\NewDocumentCommand{\findLargest}{ O{}m }
 {
  \num[
    scientific-notation = fixed,
    fixed-exponent = 0,
    group-digits=false,
    #1
  ] { \engbird_compute_max:n { #2 } }
 }

\cs_new:Npn \engbird_find_largest:nn #1 #2
 {
  \engbird_compute_max:V \l_engbird_largest_tl
 }
% syntactic sugar
\cs_new:Npn \engbird_compute_max:n #1
 {
  \fp_eval:n { max (#1) }
 }
\cs_generate_variant:Nn \engbird_compute_max:n { V }

\ExplSyntaxOff

\begin{document}

\findLargest{1, 2 ,3, 6, 3,1}

\findLargest[group-digits=true]{10000,20000}

\findLargest[round-mode=places]{ 1.5, sqrt(2), pi/2 }

\end{document}

enter image description here

  • Thanks this works perfectly. I checked xparse for documentation but didn't find anything about \cs type structure. Where can I go to learn more about this syntax? – EngBIRD Apr 11 '15 at 21:10
  • @EngBIRD You should do texdoc expl3 – egreg Apr 11 '15 at 21:13
  • Awesome, I will look into this. One more small question. When I am programming in a language that doesn't handle scope well, or has limited capabilities to update or redefine the variable in function arguments, I prefer to save to a variable that will be able to be updated and remain accessible without posing scope problems. Eg. in this answer makes continuous reference to #1 and #2. If I were to expand these functions to more dynamically process 1 and 2 and update their values would I be correct in assuming that #1 can't be updated, but could be copied into another defined variable? – EngBIRD Apr 11 '15 at 21:20
  • @EngBIRD I couldn't understand a word, sorry. – egreg Apr 11 '15 at 21:21
  • My preferred approach upon entering a custom function or macro would be to use the current index (i.e element of the string parsed and subsequently iterated through) to another variable, i.e. tmp so that it can be used in decisions prior to the max(#2) evaluation itself. Specifically, I might want to parse the #2 or tmp to determine if it is a valid gls label so that I can accept manually entered numbers as well as numbers retrieved by gls. If a glslabel is found, I would update the variable with the result of glsentryname{tmp} – EngBIRD Apr 11 '15 at 21:29

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.