TransWikia.com

Position of largest element in a list

TeX - LaTeX Asked on May 28, 2021

Consider the following:

documentclass{article}

usepackage{expl3}

ExplSyntaxOn
  cs_new_eq:NN calc fp_eval:n
ExplSyntaxOff

defvalueA{7}
defvalueB{19}
defvalueC{41}
defvalueD{31}
defvalueE{25}
defvalueF{17}
defvalueG{7}
defvalueH{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.

4 Answers

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

defvalueA{7}
defvalueB{19}
defvalueC{41}
defvalueD{31}
defvalueE{25}
defvalueF{17}
defvalueG{7}
defvalueH{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

defvalueA{7}
defvalueB{19}
defvalueC{41}
defvalueD{31}
defvalueE{25}
defvalueF{17}
defvalueG{7}
defvalueH{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.

Correct answer by Joseph Wright on May 28, 2021

Here is an etoolbox:

enter image description here

documentclass{article}

usepackage{expl3,etoolbox}

ExplSyntaxOn
  cs_new_eq:NN calc fp_eval:n
ExplSyntaxOff

defvalueA{7}
defvalueB{19}
defvalueC{41}
defvalueD{31}
defvalueE{25}
defvalueF{17}
defvalueG{7}
defvalueH{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.

Answered by Werner on May 28, 2021

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}

defvalueA{7}
defvalueB{19}
defvalueC{41}
defvalueD{31}
defvalueE{25}
defvalueF{17}
defvalueG{7}
defvalueH{3}

defmylist{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
defmaxoflist #1{romannumeral0expandafter
                    maxoflist@aromannumeral-`0#1,,}
defmaxoflist@a #1,{maxoflist@c {numexpr#1relax}}
defmaxoflist@c #1#2,{%
    ifxrelax #2relaxexpandaftermaxoflist@end
    elseifnum#2>#1expandafterexpandafterexpandaftermaxoflist@update
               elseexpandafterexpandafterexpandaftermaxoflist@next
    fifi {#1}{#2}}
defmaxoflist@end    #1#2{expandafterspacethe#1}
defmaxoflist@update #1#2{maxoflist@c {numexpr#2relax}}
defmaxoflist@next   #1#2{maxoflist@c {#1}}

% max position
defmaxposition #1{romannumeral0expandafter
                    maxposition@aromannumeral-`0#1,,}
defmaxposition@a #1,{maxposition@c 21{numexpr#1relax}}
defmaxposition@b #1%
   {expandaftermaxposition@cexpandafter {thenumexpr #1+@ne}}%
defmaxposition@c #1#2#3#4,{%
    ifxrelax #4relaxexpandaftermaxposition@end
    elseifnum#4>#3expandafterexpandafterexpandaftermaxposition@update
               elseexpandafterexpandafterexpandaftermaxposition@next
    fifi {#1}{#2}{#3}{#4}}
defmaxposition@end #1#2#3#4{ #2}
defmaxposition@update #1#2#3#4{maxposition@b {#1}{#1}{numexpr#4relax}}
defmaxposition@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 $maxoflistmylist$ (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 `$maxpositionmylist$'.)

end{document}

maxposition

Answered by user4686 on May 28, 2021

With pgfmath:

enter image description here

documentclass[a4paper]{article}
usepackage{tikz}
begin{document}
defmylist{7, 19, 41, 31, 25, 17, 7, 3}
pgfmathtruncatemacroMax{max(mylist)}

foreach[count=Pos] k in mylist {
pgfmathsetmacrotest{k==Max ?  Pos :  0}
ifnumtest=0 else xdefMaxPos{test} fi
}

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

Answered by cis on May 28, 2021

Add your own answers!

Ask a Question

Get help from others!

© 2024 TransWikia.com. All rights reserved. Sites we Love: PCI Database, UKBizDB, Menu Kuliner, Sharing RPP