This code:
[0..100]
|> Seq.map (fun i -> printfn "%A" i)
iterates only 5 elements:
> [0..100]
- |> Seq.map (fun i -> printfn "%A" i);;
0
1
2
3
4
val it : seq<unit> = seq [(); (); (); (); ...]
Why? How can I force it to eval all elements?
This happens here: The expression
[0..100] |> Seq.map (fun i -> printfn "%A" i)
computes into a sequence of units, visualized as "()". This is not what you normally want. You can see that the function inside the map returns units by FSI's (f# interactive) output:
val it : seq<unit> = seq [(); (); (); (); ...]
You would get the same result if you write
[0..100] |> Seq.map (fun _ -> ())
But in contrast to (fun _ -> ()), the function (fun i -> printfn "%A" i) has the side effect of printing to the console. This is why you see the numbers printed before the result [(); (); (); ()]
The reason why there are 5 numbers printed is an FSI internal: When it prints sequences, which are enumerable collections, it just enumerates the first few. Here it enumerates the first 5 elements and displays the first 4, which is [(); (); (); ()]
What you really want is a map function that accepts a value and returns a new value, in other words a function that maps one value to another value:
[0..100] |> Seq.map (fun i -> i * 2)
val it : seq<int> = seq [0; 2; 4; 6; ...]
As you see, this returns a result of sequence. Again, FSI only shows the first few elements of the sequence. If you transform the sequence into a list you see more elements (but still not all here, since 100 are so many):
[0..100] |> Seq.map (fun i -> i * 2) |> Seq.toList
val it : int list =
[0; 2; 4; 6; 8; 10; 12; 14; 16; 18; 20; 22; 24; 26; 28; 30; 32; 34; 36; 38;
40; 42; 44; 46; 48; 50; 52; 54; 56; 58; 60; 62; 64; 66; 68; 70; 72; 74; 76;
78; 80; 82; 84; 86; 88; 90; 92; 94; 96; 98; 100; 102; 104; 106; 108; 110;
112; 114; 116; 118; 120; 122; 124; 126; 128; 130; 132; 134; 136; 138; 140;
142; 144; 146; 148; 150; 152; 154; 156; 158; 160; 162; 164; 166; 168; 170;
172; 174; 176; 178; 180; 182; 184; 186; 188; 190; 192; 194; 196; 198; ...]
This abbreviation comes from FSI, which terminates the length of output of expressions. You can configure the length of these outputs with fsi.PrintLength, PrintWidth and so on. See the docs.
If you want to enumerate all elements of a sequence of list you can write utility functions like
let plo xs = xs |> Seq.iter (printfn "%O")
[0..10] |> Seq.map (fun i -> i * 2) |> Seq.toList |> plo
>
0
2
4
6
8
10
12
14
16
18
20
val it : unit = ()
if you use replace Seq with List, it forces to eval all elements
List has a fixed number of items, it make sense to process them all.
Seq is dealing with IEnumerable, which allows to have infinite items,
so it does not even try.
Related
I've been at this for a few hours now, looking though every website and piece of documentation I could. I can't figure out how to remove one, and only one element (In this case, a string) from an array, keeping any duplicates in tact.
I did find a way, but, it's absolutely atrocious:
let remItem gs item =
if (chkItem gs item) then
let mutable fr = [| |] //temporary array
let mutable don = false //check if we found the element
for i in gs.inventory do
if not (i = item) && don then
fr <- (Array.append fr [|i|])
//add to the temp array until we find our item
elif i = item && don = false then don <- true
//we found it, skip just once so it doesn't get added
elif don then fr <- (Array.append fr [|i|])
//now just add everything else to the temp array
{ gs with inventory = fr }
else gs
I wrote this and I barely know how it works. Please tell me there's a better way to do this. I know the mutable variables aren't needed, but I've written a dozen equally horrendous-looking pure functions and concluded this is the best that I could do. I've tried a lot of the Array.* recursive functions already, I can't seem to make any of those comply with what I want either. I just want to know if it's even possible to do this neatly and purely in F#.
I think the easiest way to do this is to first look for the index (it's an array after all) and then just cut this out - this is (I think) a good compromise between performance and pureness - it's a pure operation but you don't get to much copy-operations:
let remove x (xs : 'a array) =
match Array.tryFindIndex ((=) x) xs with
| Some 0 -> xs.[1..]
| Some i -> Array.append xs.[..i-1] xs.[i+1..]
| None -> xs
please note that you have to take care of it beeing the first index because xs.[..(-1)] will throw an exception (while the other edge-case is ok):
> remove 0 [|1..10|];;
val it : int [] = [|1; 2; 3; 4; 5; 6; 7; 8; 9; 10|]
> remove 1 [|1..10|];;
val it : int [] = [|2; 3; 4; 5; 6; 7; 8; 9; 10|]
> remove 3 [|1..10|];;
val it : int [] = [|1; 2; 4; 5; 6; 7; 8; 9; 10|]
> remove 9 [|1..10|];;
val it : int [] = [|1; 2; 3; 4; 5; 6; 7; 8; 10|]
> remove 10 [|1..10|];;
val it : int [] = [|1; 2; 3; 4; 5; 6; 7; 8; 9|]
> remove 11 [|1..10|];;
val it : int [] = [|1; 2; 3; 4; 5; 6; 7; 8; 9; 10|]
if you need even more performance you could create an empty array and use a more imperative style to copy the parts:
let remove x (xs : 'a array) =
match Array.tryFindIndex ((=) x) xs with
| Some i ->
let res = Array.zeroCreate (xs.Length-1)
if i >= 1 then
System.Array.Copy(xs,0,res,0,i)
if i+1 < xs.Length then
System.Array.Copy(xs,i+1,res,i,xs.Length-i-1)
res
| None -> xs
Remove the first occurrence of a item from a list (taken from http://www.fssnip.net/1T):
let rec remove_first pred lst =
match lst with
| h::t when pred h -> t
| h::t -> h::remove_first pred t
| _ -> []
Usage:
let somelist = [('a',2);('f',7);('a',4);('h',10)]
let removed = somelist |> remove_first (fun (x,y) -> x='a')
// Result is:
// [('f',7);('a',4);('h',10)]
Fold should do the trick:
let remove x a =
Array.fold
(fun (s,found) t ->
if found || t <> x then Array.append s [|t|],found
else s,true) ([||],false) a |> fst
Example usage:
remove 2 [|1; 2; 3; 4; 2; 5|]
val it : int [] = [|1; 3; 4; 2; 5|]
I'm recently new to F# so please bear with me. The problem i have is I'm trying to find only prime numbers.
I've write this code:
let isPrime n =
let rec check i =
i > n/2 || (n % i <> 0 && check (i + 1))
check 2;;
let listNums = List.filter isPrime >> List.length;;
let nums = [ 16; 17; 3; 4; 2; 5; 11; 6; 7; 18; 13; 14; ];;
let countPrimes (x:int) = x |> List.ofSeq |> listNums;;
trying to call
countPrimes nums;;
but this is failed with message:
The type 'int' is not compatible with the type 'seq<'a>'
any help would be appreciated
I found the solution
let isPrime n =
let rec check i =
i > n/2 || (n % i <> 0 && check (i + 1))
check 2;;
let listNums = List.filter isPrime >> List.length;;
let nums = [| 16; 17; 3; 4; 2; 5; 11; 6; 7; 18; 13; 14; |];;
let countPrimes (x:int[]) = x |> List.ofSeq |> listNums;;
countPrimes nums;;
Thanks all!
x |> List.ofSeq
seems to be the problem to me. You are passing an int into a function that requires a list. List.toSeq changes a list into a sequence. You want the function countPrimes to take a List of integers, not simply an integer. Although Carsten is right, listNums already takes a List of integers (edit: and computes the value you want provided isPrime is correct).
You do not need to countPrimes separately. Enough to remove and will work:
let isPrime n =
let rec check i =
i > n/2 || (n % i <> 0 && check (i + 1))
check 2
let nums = [ 16; 17; 3; 4; 2; 5; 11; 6; 7; 18; 13; 14; ]
let listPrime lst =
lst |> List.filter isPrime
nums |> listPrime |> printfn "%A"
Out:
[17; 3; 2; 5; 11; 7; 13]
Link:
https://dotnetfiddle.net/nVXwZ5
This question has already been asked for more general contexts. However, in this specific context:
open System.Collections.Generic
#time
// s1 and s2 are both two ordered sets of numbers
// i.e. the both s1 and s2 do not contain duplicates
let inline calcSeq op (s1: 'a list) (s2: 'a list) =
let m = new HashSet<'a>()
for x1 in s1 do
for x2 in s2 do
m.Add(x1 |> op <| x2) |> ignore
m
|> Seq.toList
let inline multLists s1 s2 = calcSeq (*) s1 s2
let inline divLists s1 s2 = calcSeq (/) s1 s2
let inline sumLists s1 s2 = calcSeq (+) s1 s2
let inline subtrLists s1 s2 = calcSeq (-) s1 s2
Is this the most efficient way to calculate the set of numbers as a result of the cross product of two sets of numbers.
Obviously the performance is O(s1 |> Seq.lenght, s2 |> Seq.length). So the performance is like:
> multLists [1..5] [1..10];;
Real: 00:00:00.002, CPU: 00:00:00.015, GC gen0: 0, gen1: 0, gen2: 0
val it : int list =
[1; 2; 3; 4; 5; 6; 7; 8; 9; 10; 12; 14; 16; 18; 20; 15; 21; 24; 27; 30; 28;
32; 36; 40; 25; 35; 45; 50]
> multLists [1..1000] [1..5000];;
Real: 00:00:02.052, CPU: 00:00:02.121, GC gen0: 100, gen1: 9, gen2: 1
val it : int list =
[1; 2; 3; 4; 5; 6; 7; 8; 9; 10; 11; 12; 13; 14; 15; 16; 17; 18; 19; 20; 21;
22; 23; 24; 25; 26; 27; 28; 29; 30; 31; 32; 33; 34; 35; 36; 37; 38; 39; 40;
41; 42; 43; 44; 45; 46; 47; 48; 49; 50; 51; 52; 53; 54; 55; 56; 57; 58; 59;
60; 61; 62; 63; 64; 65; 66; 67; 68; 69; 70; 71; 72; 73; 74; 75; 76; 77; 78;
79; 80; 81; 82; 83; 84; 85; 86; 87; 88; 89; 90; 91; 92; 93; 94; 95; 96; 97;
98; 99; 100; ...]
But maybe there are some clever tricks I can do to make this faster?
Note, for example, that if you multLists [1..2] [1..3] you get [1;2;3;4;6], skipping 5, while multiplying [1..1000] with [1..5000] gives at least a list of [1..100] without skipping any. However, there will be duplicates further on.
P.m. If you care to down vote this question, please take some time to explain, I might learn something.
Well as it has been posted before, basically this will have an O(n*m) performance, so really bad! Just having hanging this in my code can get me into trouble.
However, as has been stated this is a particular use case scenario. What I tried to achieve was to come up with a set of possible answers to the cross product of performing a calculation between two sets of numbers. So, actually, I did not need ALL the answers, just a reasonable list of options.
For my use case, when you prescribe something 3 or 4 times a day and you can pick between 1 and 5 tablets per time, you'll get the following range of possibilities to pick from to get the daily total: multiplyLists [3;4] [1..5] = [3; 6; 9; 12; 15; 4; 8; 16; 20]. In reality its a bit more complicated than that, but it boils down to this principle. So, I want to prevent the user from deciding that 5 tablets per day was a viable option given the restrictions.
So, the solution was trivial (just did not realise it for a long time;-():
let maximize n (set: list<_>) =
let max = set.Length
if n >= max then set
else
let set = set |> Seq.sort
let nth = max / (n - 1)
let i = ref 0
[ for x in set do
if !i % nth = 0 then
yield x
i := !i + 1 ]
let inline calcSeq op (s1: 'a list) (s2: 'a list) =
let m = new HashSet<'a>()
let s1 = s1 |> maximize 100
let s2 = s2 |> maximize 100
for x1 in s1 do
for x2 in s2 do
m.Add(op x1 x2) |> ignore
m
|> Seq.toList
let inline multLists s1 s2 = calcSeq (*) s1 s2
let inline divLists s1 s2 = calcSeq (/) s1 s2
let inline sumLists s1 s2 = calcSeq (+) s1 s2
let inline subtrLists s1 s2 = calcSeq (-) s1 s2
I want to create a list of 20 random numbers. I wrote this:
let numberList = [ 1 .. 20 ]
let randoms =
numberList
|> List.map (fun (x) -> System.Random().Next(0,9))
And I got this:
val numberList : int list =
[1; 2; 3; 4; 5; 6; 7; 8; 9; 10; 11; 12; 13; 14; 15; 16; 17; 18; 19; 20]
val randoms : int list =
[7; 7; 7; 7; 7; 7; 7; 7; 7; 7; 7; 7; 7; 7; 7; 7; 7; 7; 7; 7]
Which makes sense. The problem is that I want to pass in a random number each time the function is evaluated like this:
let numberList = [ 1 .. 20 ]
let randoms =
numberList
|> List.map (fun (Random().Next(0,9)) -> x)
but I am getting a "The pattern discriminator 'Random' is not defined" exception.
Am i approaching this problem the wrong way?
Thanks in advance
In your original version, you create a new Random object at each iteration. As this is seeded with the current time, you always create the same sequence.
You need to create the object outside map like so
let RNG = new System.Random()
numberlist |> List.map (fun x -> RNG.Next(0,9))
Although a more elegant solution would be
let RNG = new System.Random()
let randoms = List.init 20 (fun _ -> RNG.Next(0,9))
Your second version fails because you are trying to treat Random as a pattern which makes no sense in this situation.
Say I have a sequence of 100 elements. Every 10th element I want a new list of the previous 10 elements. In this case I will end up with a list of 10 sublists.
Seq.take(10) looks promising, how can I repeatedly call it to return a list of lists?
now there's Seq.chunkBySize available:
[1;2;3;4;5] |> Seq.chunkBySize 2 = seq [[|1; 2|]; [|3; 4|]; [|5|]]
This is not bad:
let splitEach n s =
seq {
let r = ResizeArray<_>()
for x in s do
r.Add(x)
if r.Count = n then
yield r.ToArray()
r.Clear()
if r.Count <> 0 then
yield r.ToArray()
}
let s = splitEach 5 [1..17]
for a in s do
printfn "%A" a
(*
[|1; 2; 3; 4; 5|]
[|6; 7; 8; 9; 10|]
[|11; 12; 13; 14; 15|]
[|16; 17|]
*)
I have an evolution of three solutions. None of them preserves the ordering of the input elements, which is hopefully OK.
My first solution is quite ugly (making use of ref cells):
//[[4; 3; 2; 1; 0]; [9; 8; 7; 6; 5]; [14; 13; 12; 11; 10]; [17; 16; 15]]
let solution1 =
let split s n =
let i = ref 0
let lst = ref []
seq {
for item in s do
if !i = n then
yield !lst
lst := [item]
i := 1
else
lst := item::(!lst)
i := !i+1
yield !lst
} |> Seq.toList
split {0..17} 5
My second solution factors out the use of ref cells in the first solution, but consequently forces the use of direct IEnumerator access (push in one side, pop out the other)!
//[[17; 16; 15]; [14; 13; 12; 11; 10]; [9; 8; 7; 6; 5]; [4; 3; 2; 1; 0]]
let solution2 =
let split (s:seq<_>) n =
let e = s.GetEnumerator()
let rec each lstlst lst i =
if e.MoveNext() |> not then
lst::lstlst
elif i = n then
each (lst::lstlst) [e.Current] 1
else
each lstlst ((e.Current)::lst) (i+1)
each [] [] 0
split {0..17} 5
My third solution is based on the second solution except it "cheats" by taking a list as input instead of a seq, which enables the most elegant solution using pattern matching as Tomas points out is lacking with seq (which is why we were forced to use direct IEnumerator access).
//[[17; 16; 15]; [14; 13; 12; 11; 10]; [9; 8; 7; 6; 5]; [4; 3; 2; 1; 0]]
let solution3 =
let split inputList n =
let rec each inputList lstlst lst i =
match inputList with
| [] -> (lst::lstlst)
| cur::inputList ->
if i = n then
each inputList (lst::lstlst) [cur] 1
else
each inputList lstlst (cur::lst) (i+1)
each inputList [] [] 0
split [0..17] 5
If preserving the ordering of the elements is important, you can use List.rev for this purpose. For example, in solution2, change the last line of the split function to:
each [] [] 0 |> List.rev |> List.map List.rev
Out of the top of my head:
let rec split size list =
if List.length list < size then
[list]
else
(list |> Seq.take size |> Seq.toList) :: (list |> Seq.skip size |> Seq.toList |> split size)
Perhaps this simple pure implementation might be useful:
let splitAt n xs = (Seq.truncate n xs, if Seq.length xs < n then Seq.empty else Seq.skip n xs)
let rec chunk n xs =
if Seq.isEmpty xs then Seq.empty
else
let (ys,zs) = splitAt n xs
Seq.append (Seq.singleton ys) (chunk n zs)
For example:
> chunk 10 [1..100];;
val it : seq<seq<int>> =
seq
[seq [1; 2; 3; 4; ...]; seq [11; 12; 13; 14; ...];
seq [21; 22; 23; 24; ...]; seq [31; 32; 33; 34; ...]; ...]
> chunk 5 [1..12];;
val it : seq<seq<int>> =
seq [seq [1; 2; 3; 4; ...]; seq [6; 7; 8; 9; ...]; seq [11; 12]]
If in doubt, use fold.
let split n = let one, append, empty = Seq.singleton, Seq.append, Seq.empty
Seq.fold (fun (m, cur, acc) x ->
if m = n then (1, one x, append acc (one cur))
else (m+1, append cur (one x), acc))
(0, empty, empty)
>> fun (_, cur, acc) -> append acc (one cur)
This has the advantage of being fully functional, yet touch each element of the input sequence only once(*) (as opposed to the Seq.take + Seq.skip solutions proposed above).
(*) Assuming O(1) Seq.append. I should certainly hope so.
I found this to be easily the fastest:
let windowChunk n xs =
let range = [0 .. Seq.length xs]
Seq.windowed n xs |> Seq.zip range
|> Seq.filter (fun d -> (fst d) % n = 0)
|> Seq.map(fun x -> (snd x))
i.e. window the list, zip with a list of integers, remove all the overlapping elements, and then drop the integer portion of the tuple.
I think that the solution from Brian is probably the most reasonable simple option. A probelm with sequences is that they cannot be easily processed with the usual pattern matching (like functional lists). One option to avoid that would be to use LazyList from F# PowerPack.
Another option is to define a computation builder for working with IEnumerator type. I wrote something like that recently - you can get it here. Then you can write something like:
let splitEach chunkSize (s:seq<_>) =
Enumerator.toSeq (fun () ->
let en = s.GetEnumerator()
let rec loop n acc = iter {
let! item = en
match item with
| Some(item) when n = 1 ->
yield item::acc |> List.rev
yield! loop chunkSize []
| Some(item) ->
yield! loop (n - 1) (item::acc)
| None -> yield acc |> List.rev }
loop chunkSize [] )
This enables using some functional patterns for list processing - most notably, you can write this as a usual recursive function (similar to the one you would write for lists/lazy lists), but it is imperative under the cover (the let! constructo of iter takes the next element and modifies the enumerator).