views:

304

answers:

2

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

Seq.maxIndex returns the index of the maximum element.

+2  A: 

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 http://stackoverflow.com/questions/1496980/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;;
Jonke
That solution will traverse the sequence many, many times (worst case n*n times). "let m = Seq.max l in Seq.findIndex (fun x -> x = m) l" would at least only traverse the sequence two times...
Johan Kullbom
Yes (there for the ref to for(i for(j )but the style (given in your answer) seems to indicate that you should use index and that feels wrong if you are learning FP and simply not just try to recode your imperative code in a functional language. I know that I maybe read more into the question than compile and answer it.
Jonke
I believe you're right - in that the index probably is not needed in the first place... :)
Johan Kullbom
+8  A: 

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

)

Johan Kullbom