How do I split up a collection by number of elements? - f#

How do I split up a collection by number of elements?
For example, if I have the following:
0,1,2,3,4,5,6,7,8
How could I partition the collection into 3 sets:
0,1,2
3,4,5
6,7,8
NOTE:
F# is extremely foreign to me. So forgive my ignorance.
Here's a TicTacToe exercise that I am trying to learn F# with.
In the code, I am using Seq.take and Seq.skip.
How could I write this differently?
module TicTacToe
open FsUnit
open NUnit.Framework
[<Test>]
let ``player has connected row`` () =
let grid = Map.empty
.Add(0, true).Add(1, true).Add(2, true)
.Add(3, true).Add(4, false).Add(5, true)
.Add(6, true).Add(7, true).Add(8, true)
let firstRowIsStreak = grid
|> Seq.take 3
|> Seq.forall (fun x -> x.Value = true)
let secondRowIsStreak = grid
|> Seq.skip 3
|> Seq.take 3
|> Seq.forall (fun x -> x.Value = true)
let thirdRowIsStreak = grid
|> Seq.skip 6
|> Seq.take 3
|> Seq.forall (fun x -> x.Value = true)
firstRowIsStreak |> should equal true
secondRowIsStreak |> should equal false
thirdRowIsStreak |> should equal true

If you have F# 4.0 you can use Seq.chunkBySize
Seq.chunkBySize 3 (seq [0;1;2;3;4;5;6;7;8])
val it : seq<int []> = seq [[|0; 1; 2|]; [|3; 4; 5|]; [|6; 7; 8|]]

Related

How to create a dependency between observables?

I want a tool for testing Rx components that would work like this:
Given an order of the events specified as a 'v seq and a key selector function (keySelector :: 'v -> 'k) I want to create a Map<'k, IObservable<'k>> where the guarantee is that the groupped observables yield the values in the global order defined by the above enumerable.
For example:
makeObservables isEven [1;2;3;4;5;6]
...should produce
{ true : -2-4-6|,
false: 1-3-5| }
This is my attempt looks like this:
open System
open System.Reactive.Linq
open FSharp.Control.Reactive
let subscribeAfter (o1: IObservable<'a>) (o2 : IObservable<'b>) : IObservable<'b> =
fun (observer : IObserver<'b>) ->
let tempObserver = { new IObserver<'a> with
member this.OnNext x = ()
member this.OnError e = observer.OnError e
member this.OnCompleted () = o2 |> Observable.subscribeObserver observer |> ignore
}
o1.Subscribe tempObserver
|> Observable.Create
let makeObservables (keySelector : 'a -> 'k) (xs : 'a seq) : Map<'k, IObservable<'a>> =
let makeDependencies : ('k * IObservable<'a>) seq -> ('k * IObservable<'a>) seq =
let makeDep ((_, o1), (k2, o2)) = (k2, subscribeAfter o1 o2)
Seq.pairwise
>> Seq.map makeDep
let makeObservable x = (keySelector x, Observable.single x)
let firstItem =
Seq.head xs
|> makeObservable
|> Seq.singleton
let dependentObservables =
xs
|> Seq.map makeObservable
|> makeDependencies
dependentObservables
|> Seq.append firstItem
|> Seq.groupBy fst
|> Seq.map (fun (k, obs) -> (k, obs |> Seq.map snd |> Observable.concatSeq))
|> Map.ofSeq
[<EntryPoint>]
let main argv =
let isEven x = (x % 2 = 0)
let splits : Map<bool, IObservable<int>> =
[1;2;3;4;5]
|> makeObservables isEven
use subscription =
splits
|> Map.toSeq
|> Seq.map snd
|> Observable.mergeSeq
|> Observable.subscribe (printfn "%A")
Console.ReadKey() |> ignore
0 // return an integer exit code
...but the results are not as expected and the observed values are not in the global order.
Apparently the items in each group are yield correctly but when the groups are merged its more like a concat then a merge
The expected output is: 1 2 3 4 5
...but the actual output is 1 3 5 2 4
What am I doing wrong?
Thanks!
You describe wanting this:
{ true : -2-4-6|,
false: 1-3-5| }
But you're really creating this:
{ true : 246|,
false: 135| }
Since there's no time gaps between the items in the observables, the merge basically has a constant race condition. Rx guarantees that element 1 of a given sequence will fire before element 2, but Merge offers no guarantees around cases like this.
You need to introduce time gaps into your observables if you want Merge to be able to re-sequence in the original order.

What's an alternative to Seq.iter so that I can return the result of the operation for the last item?

What's an alternative to Seq.iter so that I can return the result of the operation for the last item?
Seq.iter returns a unit. However, I want to iterate through my collection and return the last result.
Consider the following code:
let updatedGrid = grid |> Map.toSeq
|> Seq.map snd
|> Seq.iter (fun c -> grid |> setCell c
NOTE: SetCell returns a new Map:
Here's the actual code:
let setCell cell (grid:Map<(int * int), Cell>) =
grid |> Map.map (fun k v -> match k with
| c when c = (cell.X, cell.Y) -> { v with State=cell.State }
| _ -> v)
let cycleThroughCells (grid:Map<(int * int), Cell>) =
let updatedGrid = grid |> Map.toSeq
|> Seq.map snd
|> Seq.iter (fun c -> grid |> setCell c
|> ignore)
updatedGrid
Again, I just want to take the result of the last operation in the iter function
[UPDATED]
I think this works (using map):
let cycleThroughCells (grid:Map<(int * int), Cell>) =
let updatedGrid = grid |> Map.toSeq
|> Seq.map snd
|> Seq.map (fun c -> grid |> setCell c)
|> Seq.last
updatedGrid
As I said in a comment, it seems like you almost certainly want a fold so that the updated grid is passed to each successive call; otherwise the modifications are all dropped except for the last one.
I think this would do the trick:
let cycleThroughCells (grid:Map<(int * int), Cell>) =
grid
|> Map.toSeq
|> Seq.map snd
|> Seq.fold (fun grid c -> grid |> setCell c) grid
and if you reorder the arguments to setCell so that the grid argument comes first then the last line can just be |> Seq.fold setCell grid.
I don't think one exists but you can define your own using fold:
let tapSeq f s = Seq.fold (fun _ x -> f x; Some(x)) None s

Get a list of invalid drive letters

let private GetDrives = seq{
let all=System.IO.DriveInfo.GetDrives()
for d in all do
//if(d.IsReady && d.DriveType=System.IO.DriveType.Fixed) then
yield d
}
let valid={'A'..'Z'}
let rec SearchRegistryForInvalidDrive (start:RegistryKey) = seq{
let validDrives=GetDrives |> Seq.map (fun x -> x.Name.Substring(0,1))
let invalidDrives= Seq.toList validDrives |> List.filter(fun x-> not (List.exists2 x b)) //(List.exists is the wrong method I think, but it doesn't compile
I followed F#: Filter items found in one list from another list but could not apply it to my problem as both the solutions I see don't seem to compile. List.Contains doesn't exist (missing a reference?) and ListA - ListB doesn't compile either.
open System.IO
let driveLetters = set [ for d in DriveInfo.GetDrives() -> d.Name.[0] ]
let unused = set ['A'..'Z'] - driveLetters
Your first error is mixing between char and string, it is good to start with char:
let all = {'A'..'Z'}
let validDrives = GetDrives |> Seq.map (fun x -> x.Name.[0])
Now invalid drive letters are those letters which are in all but not in validDrives:
let invalidDrives =
all |> Seq.filter (fun c -> validDrives |> List.forall ((<>) c))
Since validDrives is traversed many times to check for membership, turning it to a set is better in this example:
let all = {'A'..'Z'}
let validDrives = GetDrives |> Seq.map (fun x -> x.Name.[0]) |> Set.ofSeq
let invalidDrives = all |> Seq.filter (not << validDrives.Contains)

F# split array of strings and return the result of split

let total = [| "1X2"; "3X4"; "5X6" |]
let oddEven = total
|> Array.map(fun x -> x.Split('X'))
I have an array of string, which is total in above example, I want to split the array by "X", as the oddEven in the above example, but I want to return 2 arrays of strings:
let odd = [| 1; 3; 5 |] and let even = [| 2; 4; 6 |]
It could be an easy task, but I can not figure it out now.
Any help is greatly appreciated!
Thanks,
You should check whether each string can split into two pieces, and unzip the result:
let total = [| "1X2"; "3X4"; "5X6" |]
let odds, evens = total |> Array.map (fun x -> match x.Split('X') with
| [|odd; even|] -> odd, even
| _ -> failwith "Wrong input")
|> Array.unzip;;
let evens, odds = total
|> (Array.map (fun x -> x.Split('X')))
|> Array.concat
|> Array.partition (fun s -> int s % 2 = 0)
EDIT: As John Palmer points out in the comments, you can use Array.collect instead of map and concat:
let evens, odds = total
|> Array.collect (fun s -> s.Split('X'))
|> Array.partition (fun s -> int s % 2 = 0);;
let odd =
oddEven |> Array.map (fun x -> x.[0])
let even =
oddEven |> Array.map (fun x -> x.[1])

f# array.filter based on a bool array

if I have array A, and I have another bool array isChosen with the same length of A how can I build a new array from A where isChosen is true? something like A.[isChosen]? I cannot use Array.filter directly since isChosen is not a function of A elements and there is no Array.filteri like Array.mapi.
zip should help:
let l = [|1;2;3|]
let f = [|true; false; true|]
let r = [| for (v, f) in Seq.zip l f do if f then yield v|]
// or
let r = (l, f) ||> Seq.zip |> Seq.filter snd |> Seq.map fst |> Seq.toArray
Try the zip operator
seq.zip A isChosen
|> Seq.filter snd
|> Seq.map fst
|> Array.ofSeq
This will create a sequence of tuples where one value is from A and the other is from isChosen. This will pair the values together and make it very easy to filter them out in a Seq.filter expression
It's not as elegant or 'functional' as the other answers, but every once in a while I like a gentle reminder that you can use loops and array indices in F#:
let A = [|1;2;3|]
let isChosen = [|true; false; true|]
let r = [| for i in 0..A.Length-1 do
if isChosen.[i] then
yield A.[i] |]
printfn "%A" r
:)
And here are two more ways, just to demonstrate (even) more F# library functions:
let A = [|1;2;3|]
let isChosen = [|true;false;true|]
let B = Seq.map2 (fun x b -> if b then Some x else None) A isChosen
|> Seq.choose id
|> Seq.toArray
let C = Array.foldBack2 (fun x b acc -> if b then x::acc else acc) A isChosen []
|> List.toArray
My personal favorite for understandability (and therefore maintainability): desco's answer
let r = [| for (v, f) in Seq.zip l f do if f then yield v|]

Resources