Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to find max's index in a Seq, List or Array in F#

Seq.max finds the max number. I'd like to have something like Seq.findIndex

Seq.maxIndex returns the index of the maximum element.

like image 863
Yin Zhu Avatar asked Jan 10 '10 12:01

Yin Zhu


People also ask

How to Get max index of array in Python?

The max() method is used to find the maximum value when a sequence of elements is given. It returns that maximum element as the function output. It accepts the sequence as the function argument. The index() method is used to find the index of a given element from a python list.

What is SEQ in F#?

The type seq<'T> is a type abbreviation for IEnumerable<'T> . This means that any type that implements the generic System. Collections. Generic. IEnumerable<'T> , which includes arrays, lists, sets, and maps in F#, and also most .


2 Answers

I believe you are looking for something like:

let maxIndex seq = 
    fst (Seq.maxBy snd (Seq.mapi (fun i x -> i, x) seq))

Note that giving this function an empty sequence will result in an ArgumentException.

(Alternatively, written in pipelining style:

let maxIndex seq =  
    seq
    |> Seq.mapi (fun i x -> i, x)
    |> Seq.maxBy snd 
    |> fst

)

like image 193
Johan Kullbom Avatar answered Sep 25 '22 17:09

Johan Kullbom


Why not simply use

let l=[1;2;5;3];;
Seq.findIndex  (fun x -> x= Seq.max l) l ;;

?

Or maybe as Johan Kullbom suggest in a comment:

"let m = Seq.max l in Seq.findIndex (fun x -> x = m) l"

if you what a little better O(n)

However, the need to get the index looks to me like a imperative "code smell" .

In FP it's usually better to use existing functions before you roll your own. I now this in the eyes of a C programmer seems like a for(i (for(j construct but I bet that you probably really don't need to know the index if you start think in FP.

More or less a duplicate of Finding index of element in a list in Haskell?

PS. I can't resist. In Haskell (ghc) the way should probably be something like

let cmpSnd (_, y1) (_, y2) = compare y1  y2

let maxIndex l= fst $ maximumBy cmpSnd $ zip [0..] l

However, since zip in F# doesn't seem to allow zip with unequal lengths of the list(?) the use of mapi is probably the way to go (my haskell version in F#)

let cmpSnd xs=  snd xs ;;

let zipIndex a= Seq.mapi (fun i x -> i,x) a;;

let maxIndex seq=fst (Seq.maxBy cmpSnd (zipIndex seq));;

and the reason is only so that I can make a list

let l= [[0;199;1];[4;4];[0;0;399]]

test with makeIndex l;; and decide that what I really want is a

let cmpSnd' (a,(xs: int list))  = Seq.sum  xs;;
let maxIndex' seq=fst (Seq.maxBy cmpSnd' (zipIndex seq));;

Now time to decomposite and make makeIndex take a function

let maxIndexF seq maxF=fst (Seq.maxBy maxF (zipIndex seq));;

val l : int list list = [[1; 2; 199]; [3; 3]; [4; 1]; [0; 299]]

> maxIndexF l cmpSnd'
;;
val it : int = 3
> maxIndexF l cmpSnd
;;
val it : int = 2

Finish it up

let maxIndexF'  maxF=fst << Seq.maxBy maxF << zipIndex ;;

maxIndexF' cmpSnd' l;;
maxIndexF' cmpSnd l;;
like image 39
Jonke Avatar answered Sep 23 '22 17:09

Jonke