I'm new to functional world and appreciate help on this one.
I want to SUPERCEDE ugly imperative code from this simple function, but don't know how to do it.
What I want is to randomly pick some element from IEnumerable (seq in F#) with a respect to probability value - second item in tuple (so item with "probability" 0.7 will be picked more often than with 0.1).
/// seq<string * float>
let probabilitySeq = seq [ ("a", 0.7); ("b", 0.6); ("c", 0.5); ("d", 0.1) ]
/// seq<'a * float> -> 'a
let randomPick probSeq =
let sum = Seq.fold (fun s dir -> s + snd dir) 0.0 probSeq
let random = (new Random()).NextDouble() * sum
// vvvvvv UGLY vvvvvv
let mutable count = random
let mutable ret = fst (Seq.hd probSeq )
let mutable found = false
for item in probSeq do
count <- count - snd item
if (not found && (count < 0.0)) then
ret <- fst item //return ret; //in C#
found <- true
// ^^^^^^ UGLY ^^^^^^
ret
////////// at FSI: //////////
> randomPick probabilitySeq;;
val it : string = "a"
> randomPick probabilitySeq;;
val it : string = "c"
> randomPick probabilitySeq;;
val it : string = "a"
> randomPick probabilitySeq;;
val it : string = "b"
I think that randomPick is pretty straightforward to implement imperatively, but functionally?
This is functional, but take list not seq (wanted).
//('a * float) list -> 'a
let randomPick probList =
let sum = Seq.fold (fun s dir -> s + snd dir) 0.0 probList
let random = (new Random()).NextDouble() * sum
let rec pick_aux p list =
match p, list with
| gt, h::t when gt >= snd h -> pick_aux (p - snd h) t
| lt, h::t when lt < snd h -> fst h
| _, _ -> failwith "Some error"
pick_aux random probList
An F# solution using the principle suggested by Matajon:
let randomPick probList =
let ps = Seq.skip 1 (Seq.scan (+) 0.0 (Seq.map snd probList))
let random = (new Random()).NextDouble() * (Seq.fold (fun acc e -> e) 0.0 ps)
Seq.find (fun (p, e) -> p >= random)
(Seq.zip ps (Seq.map fst probList))
|> snd
But I would probably also use a list-based approach in this case since the sum of the probability values needs to be precalculated anyhow...
I will provide only Haskell version since I don't have F# present on my notebook, it should be similar. The principle is to convert your sequence to sequence like
[(0.7,"a"),(1.3,"b"),(1.8,"c"),(1.9,"d")]
where each first element in the tuple is representing not probablity but something like range. Then it is easy, pick one random number from 0 to last number (1.9) and check in which range it belongs to. For example if 0.5 is chosen, it will be "a" because 0.5 is lower than 0.7.
Haskell code -
probabilitySeq = [("a", 0.7), ("b", 0.6), ("c", 0.5), ("d", 0.1)]
modifySeq :: [(String, Double)] -> [(Double, String)]
modifySeq seq = modifyFunction 0 seq where
modifyFunction (_) [] = []
modifyFunction (acc) ((a, b):xs) = (acc + b, a) : modifyFunction (acc + b) xs
pickOne :: [(Double, String)] -> IO String
pickOne seq = let max = (fst . last) seq in
do
random <- randomRIO (0, max)
return $ snd $ head $ dropWhile (\(a, b) -> a < random) seq
result :: [(String, Double)] -> IO String
result = pickOne . modifySeq
Example -
*Main> result probabilitySeq
"b"
*Main> result probabilitySeq
"a"
*Main> result probabilitySeq
"d"
*Main> result probabilitySeq
"a"
*Main> result probabilitySeq
"a"
*Main> result probabilitySeq
"b"
*Main> result probabilitySeq
"a"
*Main> result probabilitySeq
"a"
*Main> result probabilitySeq
"a"
*Main> result probabilitySeq
"c"
*Main> result probabilitySeq
"a"
*Main> result probabilitySeq
"c"
The way I understand it, you're logic works like this:
Sum all the weights, then select a random double somewhere between 0 and the sum of all the weights. Find the item which corresponds to your probability.
In other words, you want to map your list as follows:
Item Val Offset Max (Val + Offset)
---- --- ------ ------------------
a 0.7 0.0 0.7
b 0.6 0.7 1.3
c 0.5 1.3 1.8
d 0.1 1.8 1.9
Transforming a list of (item, probability) to (item, max) is straightforward:
let probabilityMapped prob =
[
let offset = ref 0.0
for (item, probability) in prob do
yield (item, probability + !offset)
offset := !offset + probability
]
Although this falls back on mutables, its pure, deterministic, and in the spirit of readable code. If you insist on avoiding mutable state, you can use this (not tail-recursive):
let probabilityMapped prob =
let rec loop offset = function
| [] -> []
| (item, prob)::xs -> (item, prob + offset)::loop (prob + offset) xs
loop 0.0 prob
Although we're threading state through the list, we're performing a map, not a fold operation, so we shouldn't use the Seq.fold or Seq.scan methods. I started writing code using Seq.scan, and it looked hacky and strange.
Whatever method you choose, once you get your list mapped, its very easy to select a randomly weighted item in linear time:
let rnd = new System.Random()
let randomPick probSeq =
let probMap =
[
let offset = ref 0.0
for (item, probability) in probSeq do
yield (item, probability + !offset)
offset := !offset + probability
]
let max = Seq.maxBy snd probMap |> snd
let rndNumber = rnd.NextDouble() * max
Seq.pick (fun (item, prob) -> if rndNumber <= prob then Some(item) else None) probMap
I would use Seq.to_list to transform the input sequence into a list and then use the list based approach. The list quoted is short enough that it shouldn't be an unreasonable overhead.
The simplest solution is to use ref to store state between calls to iterator for any suitable function from Seq module:
let probabilitySeq = seq [ ("a", 0.7); ("b", 0.6); ("c", 0.5); ("d", 0.1) ]
let randomPick probSeq =
let sum = Seq.fold (fun s (_,v) -> s + v) 0.0 probSeq
let random = ref (System.Random().NextDouble() * sum)
let aux = function
| _,v when !random >= v ->
random := !random - v
None
| s,_ -> Some s
match Seq.first aux probSeq with
| Some r -> r
| _ -> fst (Seq.hd probSeq)
I would use your functional, list-based version, but adapt it to use LazyList from the F# PowerPack. Using LazyList.of_seq will give you the moral equivalent of a list, but without evaluating the whole thing at once. You can even pattern match on LazyLists with the LazyList.(|Cons|Nil|) pattern.
I think that cfern's suggestion is actually simplest (?= best) solution to this.
Entire input needs to be evaluated, so seq's advantage of yield-on-demand is lost anyway. Easiest seems to take sequence as input and convert it to a list and total sum at the same time. Then use the list for the list-based portion of the algorithm (list will be in reverse order, but that doesn't matter for the calculation).
let randomPick moveList =
let sum, L = moveList
|> Seq.fold (fun (sum, L) dir -> sum + snd dir, dir::L) (0.0, [])
let rec pick_aux p list =
match p, list with
| gt, h::t when gt >= snd h -> pick_aux (p - snd h) t
| lt, h::t when lt < snd h -> fst h
| _, _ -> failwith "Some error"
pick_aux (rand.NextDouble() * sum) L
Thanks for Yours solutions, especially Juliet and Johan (I've to read it few times to actually get it).
:-)
Related
I am interested to implement fold3, fold4 etc., similar to List.fold and List.fold2. e.g.
// TESTCASE
let polynomial (x:double) a b c = a*x + b*x*x + c*x*x*x
let A = [2.0; 3.0; 4.0; 5.0]
let B = [1.5; 1.0; 0.5; 0.2]
let C = [0.8; 0.01; 0.001; 0.0001]
let result = fold3 polynomial 0.7 A B C
// 2.0 * (0.7 ) + 1.5 * (0.7 )^2 + 0.8 * (0.7 )^3 -> 2.4094
// 3.0 * (2.4094) + 1.0 * (2.4094)^2 + 0.01 * (2.4094)^3 -> 13.173
// 4.0 * (13.173) + 0.5 * (13.173)^2 + 0.001 * (13.173)^3 -> 141.75
// 5.0 * (141.75) + 0.2 * (141.75)^2 + 0.0001 * (141.75)^3 -> 5011.964
//
// Output: result = 5011.964
My first method is grouping the 3 lists A, B, C, into a list of tuples, and then apply list.fold
let fold3 f x A B C =
List.map3 (fun a b c -> (a,b,c)) A B C
|> List.fold (fun acc (a,b,c) -> f acc a b c) x
// e.g. creates [(2.0,1.5,0.8); (3.0,1.0,0.01); ......]
My second method is to declare a mutable data, and use List.map3
let mutable result = 0.7
List.map3 (fun a b c ->
result <- polynomial result a b c // Change mutable data
// Output intermediate data
result) A B C
// Output from List.map3: [2.4094; 13.17327905; 141.7467853; 5011.963942]
// result mutable: 5011.963942
I would like to know if there are other ways to solve this problem. Thank you.
For fold3, you could just do zip3 and then fold:
let polynomial (x:double) (a, b, c) = a*x + b*x*x + c*x*x*x
List.zip3 A B C |> List.fold polynomial 0.7
But if you want this for the general case, then you need what we call "applicative functors".
First, imagine you have a list of functions and a list of values. Let's assume for now they're of the same size:
let fs = [ (fun x -> x+1); (fun x -> x+2); (fun x -> x+3) ]
let xs = [3;5;7]
And what you'd like to do (only natural) is to apply each function to each value. This is easily done with List.map2:
let apply fs xs = List.map2 (fun f x -> f x) fs xs
apply fs xs // Result = [4;7;10]
This operation "apply" is why these are called "applicative functors". Not just any ol' functors, but applicative ones. (the reason for why they're "functors" is a tad more complicated)
So far so good. But wait! What if each function in my list of functions returned another function?
let f1s = [ (fun x -> fun y -> x+y); (fun x -> fun y -> x-y); (fun x -> fun y -> x*y) ]
Or, if I remember that fun x -> fun y -> ... can be written in the short form of fun x y -> ...
let f1s = [ (fun x y -> x+y); (fun x y -> x-y); (fun x y -> x*y) ]
What if I apply such list of functions to my values? Well, naturally, I'll get another list of functions:
let f2s = apply f1s xs
// f2s = [ (fun y -> 3+y); (fun y -> 5+y); (fun y -> 7+y) ]
Hey, here's an idea! Since f2s is also a list of functions, can I apply it again? Well of course I can!
let ys = [1;2;3]
apply f2s ys // Result: [4;7;10]
Wait, what? What just happened?
I first applied the first list of functions to xs, and got another list of functions as a result. And then I applied that result to ys, and got a list of numbers.
We could rewrite that without intermediate variable f2s:
let f1s = [ (fun x y -> x+y); (fun x y -> x-y); (fun x y -> x*y) ]
let xs = [3;5;7]
let ys = [1;2;3]
apply (apply f1s xs) ys // Result: [4;7;10]
For extra convenience, this operation apply is usually expressed as an operator:
let (<*>) = apply
f1s <*> xs <*> ys
See what I did there? With this operator, it now looks very similar to just calling the function with two arguments. Neat.
But wait. What about our original task? In the original requirements we don't have a list of functions, we only have one single function.
Well, that can be easily fixed with another operation, let's call it "apply first". This operation will take a single function (not a list) plus a list of values, and apply this function to each value in the list:
let applyFirst f xs = List.map f xs
Oh, wait. That's just map. Silly me :-)
For extra convenience, this operation is usually also given an operator name:
let (<|>) = List.map
And now, I can do things like this:
let f x y = x + y
let xs = [3;5;7]
let ys = [1;2;3]
f <|> xs <*> ys // Result: [4;7;10]
Or this:
let f x y z = (x + y)*z
let xs = [3;5;7]
let ys = [1;2;3]
let zs = [1;-1;100]
f <|> xs <*> ys <*> zs // Result: [4;-7;1000]
Neat! I made it so I can apply arbitrary functions to lists of arguments at once!
Now, finally, you can apply this to your original problem:
let polynomial a b c (x:double) = a*x + b*x*x + c*x*x*x
let A = [2.0; 3.0; 4.0; 5.0]
let B = [1.5; 1.0; 0.5; 0.2]
let C = [0.8; 0.01; 0.001; 0.0001]
let ps = polynomial <|> A <*> B <*> C
let result = ps |> List.fold (fun x f -> f x) 0.7
The list ps consists of polynomial instances that are partially applied to corresponding elements of A, B, and C, and still expecting the final argument x. And on the next line, I simply fold over this list of functions, applying each of them to the result of the previous.
You could check the implementation for ideas:
https://github.com/fsharp/fsharp/blob/master/src/fsharp/FSharp.Core/array.fs
let fold<'T,'State> (f : 'State -> 'T -> 'State) (acc: 'State) (array:'T[]) =
checkNonNull "array" array
let f = OptimizedClosures.FSharpFunc<_,_,_>.Adapt(f)
let mutable state = acc
for i = 0 to array.Length-1 do
state <- f.Invoke(state,array.[i])
state
here's a few implementations for you:
let fold2<'a,'b,'State> (f : 'State -> 'a -> 'b -> 'State) (acc: 'State) (a:'a array) (b:'b array) =
let mutable state = acc
Array.iter2 (fun x y->state<-f state x y) a b
state
let iter3 f (a: 'a[]) (b: 'b[]) (c: 'c[]) =
let f = OptimizedClosures.FSharpFunc<_,_,_,_>.Adapt(f)
if a.Length <> b.Length || a.Length <> c.Length then failwithf "length"
for i = 0 to a.Length-1 do
f.Invoke(a.[i], b.[i], c.[i])
let altIter3 f (a: 'a[]) (b: 'b[]) (c: 'c[]) =
if a.Length <> b.Length || a.Length <> c.Length then failwithf "length"
for i = 0 to a.Length-1 do
f (a.[i]) (b.[i]) (c.[i])
let fold3<'a,'b,'State> (f : 'State -> 'a -> 'b -> 'c -> 'State) (acc: 'State) (a:'a array) (b:'b array) (c:'c array) =
let mutable state = acc
iter3 (fun x y z->state<-f state x y z) a b c
state
NB. we don't have an iter3, so, implement that. OptimizedClosures.FSharpFunc only allow up to 5 (or is it 7?) params. There are a finite number of type slots available. It makes sense. You can go higher than this, of course, without using the OptimizedClosures stuff.
... anyway, generally, you don't want to be iterating too many lists / arrays / sequences at once. So I'd caution against going too high.
... the better way forward in such cases may be to construct a record or tuple from said lists / arrays, first. Then, you can just use map and iter, which are already baked in. This is what zip / zip3 are all about (see: "(array1.[i],array2.[i],array3.[i])")
let zip3 (array1: _[]) (array2: _[]) (array3: _[]) =
checkNonNull "array1" array1
checkNonNull "array2" array2
checkNonNull "array3" array3
let len1 = array1.Length
if len1 <> array2.Length || len1 <> array3.Length then invalidArg3ArraysDifferent "array1" "array2" "array3" len1 array2.Length array3.Length
let res = Microsoft.FSharp.Primitives.Basics.Array.zeroCreateUnchecked len1
for i = 0 to res.Length-1 do
res.[i] <- (array1.[i],array2.[i],array3.[i])
res
I'm working with arrays at the moment, so my solution pertained to those. Sorry about that. Here's a recursive version for lists.
let fold3 f acc a b c =
let mutable state = acc
let rec fold3 f a b c =
match a,b,c with
| [],[],[] -> ()
| [],_,_
| _,[],_
| _,_,[] -> failwith "length"
| ahead::atail, bhead::btail, chead::ctail ->
state <- f state ahead bhead chead
fold3 f atail btail ctail
fold3 f a b c
i.e. we define a recursive function within a function which acts upon/mutates/changes the outer scoped mutable acc variable (a closure in functional speak). Finally, this gets returned.
It's pretty cool how much type information gets inferred about these functions. In the array examples above, mostly I was explicit with 'a 'b 'c. This time, we let type inference kick in. It knows we're dealing with lists from the :: operator. That's kind of neat.
NB. the compiler will probably unwind this tail-recursive approach so that it is just a loop behind-the-scenes. Generally, get a correct answer before optimising. Just mentioning this, though, as food for later thought.
I think the existing answers provide great options if you want to generalize folding, which was your original question. However, if I simply wanted to call the polynomial function on inputs specified in A, B and C, then I would probably do not want to introduce fairly complex constructs like applicative functors with fancy operators to my code base.
The problem becomes a lot easier if you transpose the input data, so that rather than having a list [A; B; C] with lists for individual variables, you have a transposed list with inputs for calculating each polynomial. To do this, we'll need the transpose function:
let rec transpose = function
| (_::_)::_ as M -> List.map List.head M :: transpose (List.map List.tail M)
| _ -> []
Now you can create a list with inputs, transpose it and calculate all polynomials simply using List.map:
transpose [A; B; C]
|> List.map (function
| [a; b; c] -> polynomial 0.7 a b c
| _ -> failwith "wrong number of arguments")
There are many ways to solve this problem. Few are mentioned like first zip3 all three list, then run over it. Using Applicate Functors like Fyodor Soikin describes means you can turn any function with any amount of arguments into a function that expects list instead of single arguments. This is a good general solution that works with any numbers of lists.
While this is a general good idea, i'm sometimes shocked that so few use more low-level tools. In this case it is a good idea to use recursion and learn more about recursion.
Recursion here is the right-tool because we have immutable data-types. But you could consider how you would implement it with mutable lists and looping first, if that helps. The steps would be:
You loop over an index from 0 to the amount of elements in the lists.
You check if every list has an element for the index
If every list has an element then you pass this to your "folder" function
If at least one list don't have an element, then you abort the loop
The recursive version works exactly the same. Only that you don't use an index to access the elements. You would chop of the first element from every list and then recurse on the remaining list.
Otherwise List.isEmpty is the function to check if a List is empty. You can chop off the first element with List.head and you get the remaining list with the first element removed by List.tail. This way you can just write:
let rec fold3 f acc l1 l2 l3 =
let h = List.head
let t = List.tail
let empty = List.isEmpty
if (empty l1) || (empty l2) && (empty l3)
then acc
else fold3 f (f acc (h l1) (h l2) (h l3)) (t l1) (t l2) (t l3)
The if line checks if every list has at least one element. If that is true
it executes: f acc (h l1) (h l2) (h l3). So it executes f and passes it the first element of every list as an argument. The result is the new accumulator of
the next fold3 call.
Now that you worked on the first element of every list, you must chop off the first element of every list, and continue with the remaining lists. You achieve that with List.tail or in the above example (t l1) (t l2) (t l3). Those are the next remaining lists for the next fold3 call.
Creating a fold4, fold5, fold6 and so on isn't really hard, and I think it is self-explanatory. My general advice is to learn a little bit more about recursion and try to write recursive List functions without Pattern Matching. Pattern Matching is not always easier.
Some code examples:
fold3 (fun acc x y z -> x + y + z :: acc) [] [1;2;3] [10;20;30] [100;200;300] // [333;222;111]
fold3 (fun acc x y z -> x :: y :: z :: acc) [] [1;2;3] [10;20;30] [100;200;300] // [3; 30; 300; 2; 20; 200; 1; 10; 100]
Let's say I have following equation . My goal is to create sequence which returns next elements of this. Here's my solution and it works:
let rec factorial(n:float) =
match n with
|0.0 -> 1.0
|n -> n * factorial(n-1.0)
let seq1 = Seq.initInfinite( fun i -> factorial(float(i)) / sqrt(float(i)+1.0) ))
Now, analogically, I would like to create sequence which return elements according to equation:
I've got some code, but it's wrong so how to make it work?
let seq2(x:float) = Seq.initInfinite(fun a -> let i = float(a)
(1.0/factorial(0.0)) + System.Math.Pow(x,i)/factorial(i) )
Can't you skip the (1.0/factorial(0.0)) part of the equation (or maybe I misunderstood the question).
edit: i.e
let seq2(x:float) =
Seq.initInfinite(fun a ->
let i = float(a) in
System.Math.Pow(x,i)/factorial(i))
edit: to truncate a seq you can use 'take' and to sum you can use 'sum'. As in
let seq2sum nbelems =
seq2 >> Seq.take nbelems >> Seq.sum
then you get seq2sum 12 3.0 equal to approx 20 :-)
The great thing about functional languages is that you can have your solution be as close an expression of the original definition as possible.
You can avoid explicit type declarations for most functions:
let rec factorial = function
| 0 -> 1
| n -> n * (factorial (n-1))
let e x n =
seq { 0 .. n }
|> Seq.map(fun i -> x ** (float i) / float (factorial i))
|> Seq.sum
In the infinite series, you will have to take the first n entries before you sum, as an infinite series will never finish evaluating:
let e' x n =
Seq.initInfinite(fun i -> x ** (float i) / float (factorial i))
|> Seq.take n
|> Seq.sum
e 1.0 10 //2.718281801
e' 1.0 10 //2.718281801
I'm trying to write a function that takes a list for example
let list = [5;23;29;1]
let x = max list // This will return 2 because 29 will be the max value and it's "indexed" at position 2
I'm not sure about how to go about writing the max function
Since my list will only contain four elements I currently have some code like this
let list = (1, newMap1 |> getScore) :: (2, newMap2 |> getScore) :: (3, newMap3 |> getScore) :: (4, newMap4 |> getScore) :: []
I consider this a terrible approach but I'm still stuck on how to return (x, _) after I find the max of (_, y). I'm very confident with imperative approaches but I'm stumped on how to do this functionally
There is a couple of ways to do this. At the low-level, you can write a recursive function to iterate and pattern match over a list. This is good exercise if you are learning F#.
Similarly, you can implement this using the fold function. Here, the idea is that we keep some state, consisting of the "best value" and the index of the best value. At each step, we either keep the original information, or update it:
let _, maxValue, maxIndex =
list |> List.fold (fun (index, maxSoFar, maxIndex) v ->
if v > maxSoFar then (index+1, v, index+1)
else (index+1, maxSoFar, maxIndex)) (-1, System.Int32.MinValue, -1)
Finally, the shortest option I can think of is to use mapi and maxBy functions:
list
|> Seq.mapi (fun i v -> i, v)
|> Seq.maxBy snd
Here's an answer only using pattern matching and recursion.
let list = [5;23;29;1]
let rec findIndexOfMaxValue (maxValue:int) indexOfMaxValue currentIndex aList =
match aList with
| [] -> indexOfMaxValue
| head::tail -> match head with
| head when head > maxValue -> findIndexOfMaxValue head currentIndex (currentIndex + 1) tail
| _ -> findIndexOfMaxValue maxValue indexOfMaxValue (currentIndex + 1) tail
[<EntryPoint>]
let main argv =
let indexOfMaxValue = findIndexOfMaxValue 0 0 0 list
printfn "The index of the maximum value is %A." indexOfMaxValue
//The index of the maximum value is 2.
0
Out of interest, I made a timing script comparing my algorithm with the other ones provided:
open System.Diagnostics
let n = 5000
let random = System.Random 543252
let randomlists =
[for i in [1..n] -> [ for i in [1..n] -> random.Next (0, n*n)]]
let stopWatch =
let sw = Stopwatch ()
sw.Start ()
sw
let timeIt (name : string) (a : int list -> 'T) : unit =
let t = stopWatch.ElapsedMilliseconds
let v = a (randomlists.[0])
for i = 1 to (n - 1) do
a randomlists.[i] |> ignore
let d = stopWatch.ElapsedMilliseconds - t
printfn "%s, elapsed %d ms, result %A" name d v
let rec findIndexOfMaxValue (maxValue:int) indexOfMaxValue currentIndex aList =
match aList with
| [] -> indexOfMaxValue
| head::tail -> match head with
| head when head > maxValue -> findIndexOfMaxValue head currentIndex (currentIndex + 1) tail
| _ -> findIndexOfMaxValue maxValue indexOfMaxValue (currentIndex + 1) tail
let findIndexOfMaxValueFoldAlg list =
let _, maxValue, maxIndex =
list |> List.fold (fun (index, maxSoFar, maxIndex) v ->
if v > maxSoFar then (index+1, v, index+1)
else (index+1, maxSoFar, maxIndex)) (-1, System.Int32.MinValue, -1)
maxIndex
let findIndexOfMaxValueSimpleSeq list = list
|> Seq.mapi (fun i v -> i, v)
|> Seq.maxBy snd
|> fst
let findIndexOfMaxValueSimpleList list =
list
|> List.mapi (fun i x -> i, x)
|> List.maxBy snd
|> fst
[<EntryPoint>]
let main argv =
timeIt "recursiveOnly" (findIndexOfMaxValue 0 0 0)
timeIt "simpleSeq" findIndexOfMaxValueSimpleSeq
timeIt "simpleList" findIndexOfMaxValueSimpleList
0
The results I get are:
recursiveOnly, elapsed 356ms, result 3562
foldAlgorithm, elapsed 1602ms, result 3562
simpleSeq, elapsed 4504ms, result 3562
simpleList, elapsed 4395ms, result 3562
I have these functions in my helper library:
module List =
let maxIndexBy projection list =
list
|> List.mapi (fun i x -> i, projection x)
|> List.maxBy snd
|> fst
let maxIndex list = maxIndexBy id list
Returns the index of the max element, optionally using a given projection function. You can write the same functions for the Seq and Array modules easily by replacing the "List" part and renaming the arguments.
I am seeking help, mainly because I am very new to F# environment. I need to use F# stream to generate an infinite stream of Armstrong Numbers. Can any one help with this one. I have done some mambo jumbo but I have no clue where I'm going.
type 'a stream = | Cons of 'a * (unit -> 'a stream)
let rec take n (Cons(x, xsf)) =
if n = 0 then []
else x :: take (n-1) (xsf());;
//to test if two integers are equal
let test x y =
match (x,y) with
| (x,y) when x < y -> false
| (x,y) when x > y -> false
| _ -> true
//to check for armstrong number
let check n =
let mutable m = n
let mutable r = 0
let mutable s = 0
while m <> 0 do
r <- m%10
s <- s+r*r*r
m <- m/10
if (test n s) then true else false
let rec armstrong n =
Cons (n, fun () -> if check (n+1) then armstrong (n+1) else armstrong (n+2))
let pos = armstrong 0
take 5 pos
To be honest your code seems a bit like a mess.
The most basic version I could think of is this:
let isArmstrong (a,b,c) =
a*a*a + b*b*b + c*c*c = (a*100+b*10+c)
let armstrongs =
seq {
for a in [0..9] do
for b in [0..9] do
for c in [0..9] do
if isArmstrong (a,b,c) then yield (a*100+b*10+c)
}
of course assuming a armstrong number is a 3-digit number where the sum of the cubes of the digits is the number itself
this will yield you:
> Seq.toList armstrongs;;
val it : int list = [0; 1; 153; 370; 371; 407]
but it should be easy to add a wider range or remove the one-digit numbers (think about it).
general case
the problem seems so interesting that I choose to implement the general case (see here) too:
let numbers =
let rec create n =
if n = 0 then [(0,[])] else
[
for x in [0..9] do
for (_,xs) in create (n-1) do
yield (n, x::xs)
]
Seq.initInfinite create |> Seq.concat
let toNumber (ds : int list) =
ds |> List.fold (fun s d -> s*10I + bigint d) 0I
let armstrong (m : int, ds : int list) =
ds |> List.map (fun d -> bigint d ** m) |> List.sum
let leadingZero =
function
| 0::_ -> true
| _ -> false
let isArmstrong (m : int, ds : int list) =
if leadingZero ds then false else
let left = armstrong (m, ds)
let right = toNumber ds
left = right
let armstrongs =
numbers
|> Seq.filter isArmstrong
|> Seq.map (snd >> toNumber)
but the numbers get really sparse quickly and using this will soon get you out-of-memory but the
first 20 are:
> Seq.take 20 armstrongs |> Seq.map string |> Seq.toList;;
val it : string list =
["0"; "1"; "2"; "3"; "4"; "5"; "6"; "7"; "8"; "9"; "153"; "370"; "371";
"407"; "1634"; "8208"; "9474"; "54748"; "92727"; "93084"]
remark/disclaimer
this is the most basic version - you can get big speed/performance if you just enumerate all numbers and use basic math to get and exponentiate the digits ;) ... sure you can figure it out
Seq.max finds the max number. I'd like to have something like Seq.findIndex
Seq.maxIndex returns the index of the maximum element.
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
)
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;;