11

Consider the following:

\documentclass{article}

\usepackage{expl3}

\ExplSyntaxOn
  \cs_new_eq:NN \calc \fp_eval:n
\ExplSyntaxOff

\def\valueA{7}
\def\valueB{19}
\def\valueC{41}
\def\valueD{31}
\def\valueE{25}
\def\valueF{17}
\def\valueG{7}
\def\valueH{3}

\begin{document}

\noindent I have the list
\[
\valueA,\valueB,\valueC,\valueD,\valueE,\valueF,\valueG,\valueH
\]
in which the largest element is $\calc{max(\valueA,\valueB,\valueC,\valueD,\valueE,\valueF,\valueG,\valueH)}$ (but that is of no importance to me).\\[\baselineskip]
How can I get \LaTeX{} to extract the position number of the largest element in a list? (In the example above, the answer is of course `$3$'.)

\end{document}

output

Note

It doesn't have to be a LaTeX 3 solution, but I need to compile the original document (i.e., the one I need the solution for) via latex --> dvips --> ps2pdf.

Also, the list is generated via the \def method.

  • 2
    I updated the tag from [tag:latex3] to [tag:expl3] because [tag:expl3] concerns the programming framework while [tag:latex3] is (supposed to be) more concerned with the project or its architecture :) I hope I'm not stepping on any toes -- feel free to add [tag:latex3] back if you think it should be so. – Sean Allred Mar 05 '15 at 20:25

4 Answers4

13

Here is an etoolbox:

enter image description here

\documentclass{article}

\usepackage{expl3,etoolbox}

\ExplSyntaxOn
  \cs_new_eq:NN \calc \fp_eval:n
\ExplSyntaxOff

\def\valueA{7}
\def\valueB{19}
\def\valueC{41}
\def\valueD{31}
\def\valueE{25}
\def\valueF{17}
\def\valueG{7}
\def\valueH{3}

\makeatletter
\newcounter{maxindex}
\newcommand{\findmaxindex}[1]{%
  \@tempcnta=0% Counter for stepping through elements
  \setlength{\@tempdima}{-\maxdimen}% "Smallest" number as a length/dimension
  \renewcommand*{\do}[1]{%
    \advance\@tempcnta by 1% Step to next element
    \ifdimgreater{##1pt}{\@tempdima}{\setlength{\@tempdima}{##1pt}\setcounter{maxindex}{\@tempcnta}}{}}% Found larger element
  \docsvlist{#1}% process list to find maximum number and index
}
\makeatother

\setlength{\parindent}{0pt}% Just for this example
\begin{document}

I have the list
\[
  7, 19, 41, 31, 25, 17, 7, 3
\]
in which the largest element is $\calc{max(7, 19, 41, 31, 25, 17, 7, 3)}$.

\findmaxindex{7, 19, 41, 31, 25, 17, 7, 3}% Find maximum number index
The position number of the largest element in this \themaxindex.

\bigskip

I have the list
\[
  \valueH,\valueG,\valueF,\valueE,\valueD,\valueC,\valueB,\valueA
\]
in which the largest element is $\calc{max(\valueH,\valueG,\valueF,\valueE,\valueD,\valueC,\valueB,\valueA)}$.

\findmaxindex{\valueH,\valueG,\valueF,\valueE,\valueD,\valueC,\valueB,\valueA}% Find maximum number index
The position number of the largest element in this \themaxindex.

\end{document}

Note that it will choose as index of the first elements that is largest. The index of the maximum number is stored in the counter maxindex, available for print via \themaxindent.

The idea is to step through the list and mark each element that is found to be greater than the previous greatest element found. Using dimensions allows for working with decimal numbers.

Werner
  • 603,163
11

Another expandable solution. No package used. (for this situation dealing only with integers, for decimals one can replace \ifnum with \ifdim up to some extent; for even more complicated situations there is, among others, xint).

\documentclass{article}

\def\valueA{7}
\def\valueB{19}
\def\valueC{41}
\def\valueD{31}
\def\valueE{25}
\def\valueF{17}
\def\valueG{7}
\def\valueH{3}

\def\mylist{\valueA,\valueB,\valueC,\valueD,\valueE,\valueF,\valueG,\valueH}

\makeatletter
% the two routines \maxoflist and \maxposition are not optimal if the
% list elements require some costly expansion to compute their values
% this could be improved, if needed, to do this expansion only once
% I here design the thing for either litteral digit tokens or 
% \count registers or the like

% naturally one could also do a single routine with a two element
% output: (earliest) position and value of the maximum

% maximum
\def\maxoflist #1{\romannumeral0\expandafter
                    \maxoflist@a\romannumeral-`0#1,,}
\def\maxoflist@a #1,{\maxoflist@c {\numexpr#1\relax}}
\def\maxoflist@c #1#2,{%
    \ifx\relax #2\relax\expandafter\maxoflist@end
    \else\ifnum#2>#1\expandafter\expandafter\expandafter\maxoflist@update
               \else\expandafter\expandafter\expandafter\maxoflist@next
    \fi\fi {#1}{#2}}
\def\maxoflist@end    #1#2{\expandafter\space\the#1}
\def\maxoflist@update #1#2{\maxoflist@c {\numexpr#2\relax}}
\def\maxoflist@next   #1#2{\maxoflist@c {#1}}

% max position
\def\maxposition #1{\romannumeral0\expandafter
                    \maxposition@a\romannumeral-`0#1,,}
\def\maxposition@a #1,{\maxposition@c 21{\numexpr#1\relax}}
\def\maxposition@b #1%
   {\expandafter\maxposition@c\expandafter {\the\numexpr #1+\@ne}}%
\def\maxposition@c #1#2#3#4,{%
    \ifx\relax #4\relax\expandafter\maxposition@end
    \else\ifnum#4>#3\expandafter\expandafter\expandafter\maxposition@update
               \else\expandafter\expandafter\expandafter\maxposition@next
    \fi\fi {#1}{#2}{#3}{#4}}
\def\maxposition@end #1#2#3#4{ #2}
\def\maxposition@update #1#2#3#4{\maxposition@b {#1}{#1}{\numexpr#4\relax}}
\def\maxposition@next   #1#2#3#4{\maxposition@b {#1}{#2}{#3}}
\makeatother


\begin{document}

\noindent I have the list
\[
\mylist
\]
in which the largest element is $\maxoflist\mylist$ (but that is 
of no importance to me).\\[\baselineskip]
How can I get \LaTeX{} to extracting the position number 
of the largest element in a list? (In the example above, 
the answer is of course `$\maxposition\mylist$'.)

\end{document}

maxposition

  • 1
    my comment about a routine doing both is a bit awkward: \maxposition already does both, it is only that in the end it prints only the position #2 and not the max value \the#3. –  Mar 05 '15 at 21:33
  • \valueE is repeated, by mistake in copy paste (I wonder how...) –  Mar 05 '15 at 21:36
  • 1
    thanks... but the mistake wasn't when I copied pasted to post the answer, but when I manipulated my emacs buffer. This shows in the image ! we are doomed to maintain these comments for the edification of future readers ;-) –  Mar 05 '15 at 21:46
10

Just using expl3 we can do this using one loop or two. A one loop version needs to work out the maximum value and track the position at the same time:

\documentclass{article}
\usepackage{expl3,xparse}
\ExplSyntaxOn
\NewDocumentCommand \maxposition { m }
  {
    \svend_clist_pos_max:n {#1}
  }
\cs_new:Npn \svend_clist_pos_max:n #1
  {
    \__svend_clist_pos_max:nnnw \c_zero \c_zero { -\c_max_int }
      #1 , \q_recursion_tail , \q_recursion_stop
  }
 \cs_new:Npn \__svend_clist_pos_max:nnnw #1#2#3#4 ,
   {
     \quark_if_recursion_tail_stop_do:nn {#4} {#1}
     \fp_compare:nNnTF {#4} > {#3}
       {
         \__svend_clist_pos_max:fnnw 
           { \int_eval:n { #1 + #2 + \c_one } } \c_zero {#4}
       }
       {
         \__svend_clist_pos_max:nfnw 
           {#1} { \int_eval:n { #2 + \c_one } } {#3}
       }
  }
\cs_generate_variant:Nn \__svend_clist_pos_max:nnnw { f , nf }
\ExplSyntaxOff

\def\valueA{7}
\def\valueB{19}
\def\valueC{41}
\def\valueD{31}
\def\valueE{25}
\def\valueF{17}
\def\valueG{7}
\def\valueH{3}

\begin{document}

\maxposition{\valueA,\valueB,\valueC,\valueD,\valueE,\valueF,\valueG,\valueH}

\end{document}

whereas a two loop version first finds the maximum then the position so there are fewer things to track in one go

\documentclass{article}
\usepackage{expl3,xparse}
\ExplSyntaxOn
\NewDocumentCommand \maxposition { m }
  {
    \svend_clist_pos_max:n {#1}
  }
\cs_new:Npn \svend_clist_pos_max:n #1
  {
    \__svend_clist_pos_max:fn
      {
        \__svend_clist_pos_max:nw { -\c_max_int }
          #1 , \q_recursion_tail , \q_recursion_stop
      } {#1}
  }
\cs_new:Npn \__svend_clist_pos_max:nw #1#2 ,
  {
    \quark_if_recursion_tail_stop_do:nn {#2} {#1}
    \fp_compare:nNnTF {#2} > {#1}
      { \__svend_clist_pos_max:nw {#2} }
      { \__svend_clist_pos_max:nw {#1} }
  }
\cs_new:Npn \__svend_clist_pos_max:nn #1#2
  {
    \__svend_clist_pos_max:nnw { 1 } {#1}
      #2 , \q_recursion_tail , \q_recursion_stop
  }
\cs_generate_variant:Nn \__svend_clist_pos_max:nn { f }
\cs_new:Npn \__svend_clist_pos_max:nnw #1#2#3 ,
  {
    \quark_if_recursion_tail_stop_do:nn {#3} {#1}
    \int_compare:nNnT {#2} = {#3}
      { \use_i_delimit_by_q_recursion_stop:nw {#1} }
    \__svend_clist_pos_max:fnw { \int_eval:n { #1 + \c_one } } {#2}
  }
\cs_generate_variant:Nn \__svend_clist_pos_max:nnw { f }


\cs_new:Npn \__svend_list_max:nw #1#2 ,
  {
    \quark_if_recursion_tail_stop_do:nn {#2} {#1}
    \int_compare:nNnTF {#2} > {#1}
      { \__svend_list_max:nw {#2} }
      { \__svend_list_max:nw {#1} }
  }
\ExplSyntaxOff

\def\valueA{7}
\def\valueB{19}
\def\valueC{41}
\def\valueD{31}
\def\valueE{25}
\def\valueF{17}
\def\valueG{7}
\def\valueH{3}

\begin{document}

\maxposition{\valueA,\valueB,\valueC,\valueD,\valueE,\valueF,\valueG,\valueH}

\end{document}

The idea is first to find the largest entry using one mapping, then to find the position of this entry using a second mapping. Everything is expandable at the code level, so you could use \DeclareExpandableDocumentCommand here if you wanted.

Joseph Wright
  • 259,911
  • 34
  • 706
  • 1,036
1

With pgfmath:

enter image description here

\documentclass[a4paper]{article}
\usepackage{tikz}
\begin{document}
\def\mylist{7, 19, 41, 31, 25, 17, 7, 3}
\pgfmathtruncatemacro\Max{max(\mylist)}

\foreach[count=\Pos] \k in \mylist { \pgfmathsetmacro\test{\k==\Max ? \Pos : 0} \ifnum\test=0 \else \xdef\MaxPos{\test} \fi }

In {\mylist} the maximum is {\Max} at list-position \MaxPos. \end{document}

cis
  • 8,073
  • 1
  • 16
  • 45