Converting string[][][] to string[][] in f# - sorting

I'm having some troubles with F# because i'm learning. I have something like the next code:
let A = [| [| [|"1";"Albert"|];[|"2";"Ben"|] |];[| [|"1";"Albert"|];[|"3";"Carl"|] |] |]
(Type A: string[][][])
I'm trying to convert A to:
let B = [| [|"1"; "Albert" |] ; [| "2"; "Ben"|] ; [| "3"; "Carl"|] |]
(Type B: string[][])
I don't know how to do this. I've been trying some for and recursive function but I don't get it.

You could use Array.concat to turn the string[][][] into string[][], and then Seq.distinct to remove the duplicate string arrays.
let b =
[| [| [|"1";"Albert"|];[|"2";"Ben"|] |];[| [|"1";"Albert"|];[|"3";"Carl"|] |] |]
|> Array.concat
|> Seq.distinct
|> Seq.toArray

Here are a couple of other options for implementing this to help you conceptualize this type of problem better:
let A = [| [| [|"1";"Albert"|];[|"2";"Ben"|] |];[| [|"1";"Albert"|];[|"3";"Carl"|] |] |]
//Matthew's answer
//This is exactly what you were asking for.
//It takes all the subarrays and combines them into one
A |> Array.concat
|> Seq.distinct
|> Seq.toArray
//This is the same thing except it combines it with a transformation step,
//although in your case, the transform isn't needed so the transform
//function is simply `id`
A |> Seq.collect id
|> Seq.distinct
|> Seq.toArray
//The same as the second one except using a comprehension.
//This form makes it somewhat more clear exactly what is happening (iterate
//the items in the array and yield each item).
//The equivalent for the first one is `[|for a in A do yield! a|]`
[for a in A do for b in a -> b]
|> Seq.distinct
|> Seq.toArray

Related

F# Bjorklund algorithm: convert while-loop to recursive function: type-constraint issue

I’m doing the deep dive into f# finally. Long time c-style imperative guy - but lover of all languages. I’m attempting the Bjorklund algorithm for Euclidean Rhythms. Bjorklund: Most equal spacing of 1’s in a binary string up to rotation, e.g. 1111100000000 -> 1001010010100.
https://erikdemaine.org/papers/DeepRhythms_CGTA/paper.pdf
I initially based my attempt off a nice js/lodash implementation. I tried from scratch but got all tied up in old concepts.
https://codepen.io/teropa/details/zPEYbY
Here's my 1:1 translation
let mutable pat = "1111100000000" // more 0 than 1
//let mutable pat = "1111111100000" // more 1 than 0
// https://stackoverflow.com/questions/17101329/f-sequence-comparison
let compareSequences = Seq.compareWith Operators.compare
let mutable apat = Array.map (fun a -> [a]) ( Seq.toArray pat )
let mutable cond = true
while cond do
let (head, rem) = Array.partition (fun v -> (compareSequences v apat.[0]) = 0) apat
cond <- rem.Length > 1
match cond with
| false -> ()
| true ->
for i=0 to (min head.Length rem.Length)-1 do
apat.[i] <-apat.[i] # apat.[^0]
apat <- apat.[.. ^1]
let tostring (ac : char list) = (System.String.Concat(Array.ofList(ac)))
let oned = (Array.map (fun a -> tostring a) apat )
let res = Array.reduce (fun a b -> a+b) oned
printfn "%A" res
That seems to work. But since I want to (learn) be as functional, not necc. idiomatic, as possible, I wanted to lose the while and recurse the main algorithm.
Now I have this:
let apat = Array.map (fun a -> [a]) ( Seq.toArray pat )
let rec bjork bpat:list<char> array =
let (head, rem) = Array.partition (fun v -> (compareSequences v bpat.[0]) = 0) bpat
match rem.Length > 1 with
| false -> bpat
| true ->
for i=0 to (min head.Length rem.Length)-1 do
bpat.[i] <-bpat.[i] # bpat.[^0]
bjork bpat.[.. ^1]
let ppat = bjork apat
The issue is the second argument to compareSequences: bpat.[0] I am getting the error:
The operator 'expr.[idx]' has been used on an object of indeterminate type based on information prior to this program point. Consider adding further type constraints
I'm a bit confused since this seems so similar to the while-loop version. I can see that the signature of compareSequences is different but don't know why. apat has the same type in each version save the mutability. bpat in 2nd version is same type as apat.
while-loop: char list -> char list -> int
rec-funct : char list -> seq<char> -> int
I will say I've had some weird errors learning f# that ended up having to do with issues elsewhere in the code so hopefully this is not a lark.
Also, there may be other ways to do this, including Bresenham's line algorithm, but I'm on the learning track and this seemed a good algorithm for several functional concepts.
Can anyone see what I am missing here? Also, if someone who is well versed in the functional/f# paradigm has a nice way of approaching this, I'd like to see that.
Thanks
Ted
EDIT:
The recursive as above does not work. Just couldn't test. This works, but still has a mutable.
let rec bjork (bbpat:list<char> array) =
let mutable bpat = bbpat
let (head, rem) = Array.partition (fun v -> (compareSequences v bpat.[0]) = 0) bpat
match rem.Length > 1 with
| false -> bpat
| true ->
for i=0 to (min head.Length rem.Length)-1 do
bpat.[i] <-bpat.[i] # bpat.[^0]
bpat <- bpat.[.. ^1]
bjork bpat
You need to put parentheses around (bpat:list<char> array). Otherwise the type annotation applies to bjork, not to bbpat:
let rec bjork (bbpat:list<char> array) =
...
Also note that calculating length and indexing are both O(n) operations on an F# linked lists. Consider pattern matching instead.

Seq.take won't return elements

When I run the following code:
getTheData() |> Seq.take 3
it does not return the elements, instead it outputs this:
val it : seq<Collections.Generic.KeyValuePair<ID,Data>>
I am using Visual Studio 2017 and F# Interactive
What is wrong, should it not output the first 3 items?
getTheData function =
let getTheData() =
(#"C:\Users\data.xlsx")
|> (ParseExcel >> datap)
|> Seq.distinct
|> Seq.map(fun b -> b.ID, b)
|> Map.ofSeq
Seq.take is not considered a terminal operation on a sequence in F#. As mentioned in the comments, sequences are lazily evaluated, and only operations that are considered "terminal" will cause a sequence to be iterated. Terminal operations include Seq.iter (if you want to perform an action on each element) and Seq.toList (if you want a materialized list of each element), as well as others like Seq.exactlyOne.
In F# interactive, you can probably just evaluate it to see the first few values. In the following example mirroring yours, evaluating it at the end will display the 3 values taken:
open System
let getTheData() =
seq {
for n in {0..1000} -> Guid.NewGuid(), n
} |> Map.ofSeq
getTheData()
|> Seq.take 3;;
it;;
val it : seq<Collections.Generic.KeyValuePair<Guid,int>> =
seq
[[001830fe-9ce3-4649-8609-571e4aedb4c7, 791]
{Key = 001830fe-9ce3-4649-8609-571e4aedb4c7;
Value = 791;};
[001bf0a9-5981-4bc0-bcaf-046af7f4866a, 383]
{Key = 001bf0a9-5981-4bc0-bcaf-046af7f4866a;
Value = 383;};
[004b44a7-85d2-4ce5-91bf-49bcc44f03ba, 91]
{Key = 004b44a7-85d2-4ce5-91bf-49bcc44f03ba;
Value = 91;}]

F# how to do List.map in parallel

What is the most lightweight, terse way to run the following code in parallel within the standard F# libs? Or failing that any widely used additional libs?
let newlist = oldlist |> List.map myComplexFunction
The best I could find was
let newlist = oldlist |> List.map (fun x -> async { return myComplexFunction x }
|> Async.Parallel
|> Async.RunSynchronously
|> Array.toList
I don't like this because it's 4 lines long and constructs an array that I then have to make back into a list. If I were working with Arrays it would be simple, Array.parallel, but I want to keep that lovely Immutable list functional purity. I just can't believe there is no list alternative, but so far have been unable to find one.
Any good suggestions?
Use the PSeq module:
open Microsoft.FSharp.Collections
let newlist =
oldlist
|> PSeq.map myComplexFunction
|> PSeq.toList
It's now worth taking a look at Array.Parallel in F# Core.
let newlist =
oldlist
|> Array.ofList
|> Array.Parallel.map (fun x -> myComplexFunction x)
|> Array.toList

Merging lists of 'spatial' tuples

I have three lists of tuples, each tuple contains (startpos, endpos, value).
What I want to do is merge these into one list of tuples (startpos, endpos, values[]), but following a rule which I find it easier to draw than to write:
//third [---------] [------------]
//second [-------------] [---------------------------]
//first [-----------------------------] [--------------]
//(pos) 0123456789|123456789|123456789|123456789|123456789|123456789|123456789
//result [--1-][--2-][---3---][---1----] [---2--][---3--]
(The numbers in result represent the expected length of the values[] list for each resulting element)
Basically, I only keep a 'higher' element where it overlaps a 'lower' element, and I split up into 'homogenous' elements.
The positions can be considered as being of type int. As you can see from the result, the 'split' segments do not start and end at the same position, but at pos-1 or pos+1. The order of the values is not important, as long as it is defined.
Sample data (based on example above):
let third = [(12,22,3.1);(43,56,3.2)]
let second = [(6,20,2.1);(35,63,2.2)]
let first = [(0,30,1.1);(35,50,1.2)]
let after = [
(0,5,[1.1]);
(6,11,[1.1;2.1]);
(12,20,[1.1;2.1;3.1]);
(21,30,[1.1]);
(35,42,[1.2;2.2]);
(43,50,[1.2;2.2;3.2])
]
Right now I'm finding it difficult to think about this in a functional way, anything that comes to mind is imperative. Maybe that's inevitable in this case, but if anyone has any ideas...
UPDATE Actually, if we generalised the input case to already be of type (int*int*List<float>), we could just treat the case of two input lists, then fold that.
PS: This is not homework, or code golf, I've just sterilised the data somewhat.
Your after data is wrong; at least my program thinks it is, and I believe it. :)
let third = [(12,22,3.1);(43,56,3.2)]
let second = [(6,20,2.1);(35,63,2.2)]
let first = [(0,30,1.1);(35,50,1.2)]
let all = List.concat [first; second; third]
let min = all |> Seq.map (fun (x,y,z)->x) |> Seq.min
let max = all |> Seq.map (fun (x,y,z)->y) |> Seq.max
let setsEachValueIsIn =
[min..max]
|> List.map (fun i ->
i, all
|> List.filter (fun (x,y,z) -> x<=i && i<=y)
|> List.map (fun (x,y,z) -> z))
printfn "%A" setsEachValueIsIn
let x1,l1 = Seq.nth 0 setsEachValueIsIn
let result =
setsEachValueIsIn
|> List.fold (fun (((l,h,s)::t) as prev) (nx,ns) ->
if s=ns then (l,nx,s)::t else (nx,nx,ns)::prev
) [x1,x1,l1]
|> List.rev
let after = [
(0,5,[1.1]);
(6,11,[1.1;2.1]);
(12,20,[1.1;2.1;3.1]);
(21,30,[1.1]);
(35,42,[1.2;2.2]);
(43,50,[1.2;2.2;3.2])
]
printfn ""
printfn "%A" result
printfn ""
printfn "%A" after
assert(result = after)
Strategy: first I map every number in the whole range to the 'sets it is in'. Then I fold, seeding with the first result as (min,min,setsMinIsIn) and every step of the way, if the set does not change, I just widen the range, else if the set does change, I make a new element.
Key for var names in the fold: low, high, set, nx-next x, ns-next set
Complete rewrite (see edits), shorter, more elegant, maybe less readable. Still pinching Brian's logic.
UPDATE: now works, at least for the test above
let third = [(12,22,3.1);(43,56,3.2)]
let second = [(6,20,2.1);(35,63,2.2)]
let first = [(0,30,1.1);(35,50,1.2)]
//===helper functions===
// foldable combined min and max finder
let minmax (mn,mx) (x,y,_) = (min mn x, max mx y)
// test if x - y range overlaps position i
let overlaps i (x,y,_) = x<=i && i<=y
// get third element from triple
let getz (_,_,z) = z
//specialise function, given two tuples, will combine lists (L & U)
// but only if both lists have contents AND their indexes (il & iu)
// are not more than 1 apart, i is included simply so that we can pass
// merge directly to the List.map2 below
let merge (i,il,L) (_,iu,U) =
if L = [] || U = [] || iu - il > 1 then
(i, il, L)
else
(i, iu, L # U)
let input = [first;second;third] // input data - 'bottom' first
//find max and min positions
let (x0,yn) = input |> Seq.concat |> Seq.fold minmax (0,0)
//transform each data list to a list of (i,[z])
let valsByPos = input |> List.map (fun level -> //for each data 'level'
[x0..yn] |> List.map (fun i -> //for each position in range
//collect values of all elements in level that
// overlap this position
(i, level |> List.filter (overlaps i) |> List.map getz)))
// 'merge up' each level, keeping only upper values if lower values exist
// after we will have just one list of (i, [z])
let mergedValsByPos = valsByPos //offside here for SO formatting
//add an index into each tuple
|> List.mapi (fun i l -> l |> List.map (fun (j,z) -> (j,i,z)))
//use index to determine if we should 'merge up' for each subsublst
|> List.reduce (List.map2 merge)
//rip the index back out
|> List.map (fun (i,_,z) -> (i,z))
//get first value as seed for fold
let x1,l1 = Seq.nth 0 mergedValsByPos
//transform list (i,[z]) into list of (x,y,[z])
//key: (l)ow, (h)igh, (s)et, (nx)-next x, (ns)-next set
let result =
mergedValsByPos
//first remove any positions where there are no values
|> List.filter (fun el -> snd(el) <> [])
//double capture on state so we can take all or part of it
|> List.fold (fun (((l,h,s)::t) as prev) (nx,ns) ->
//if [z] value hasn't changed, we just enlarge range
// of current state (from (l,h) to (l,nx))
// otherwise we add a new element (nx,nx,ns) to state
if s=ns then (l,nx,s)::t else (nx,nx,ns)::prev
) [x1,x1,l1] //initial state from seed values
|> List.rev //folded value is backwards (because of::), so reverse

Using the F# pipe symbol with an object constructor

I'm trying to figure out the correct syntax to use the pipe operator |> into the creation of an object. Currently I'm using a static member to create the object and just piping to that. Here is the simplified version.
type Shape =
val points : Vector[]
new (points) =
{ points = points; }
static member create(points) =
Shape(points)
static member concat(shapes : Shape list) =
shapes
|> List.map (fun shape -> shape.points)
|> Array.concat
|> Shape.create
What I want to do ...
static member concat(shapes : Shape list) =
shapes
|> List.map (fun shape -> shape.points)
|> Array.concat
|> (new Shape)
Is something like this possible? I don't want to duplicate code by repeating my constructor with the static member create.
Update
Constructors are first-class functions as of F# 4.0
In F# 4.0 the correct syntax is.
static member concat(shapes : Shape list) =
shapes
|> List.map (fun shape -> shape.points)
|> Array.concat
|> Shape
There's always
(fun args -> new Shape(args))
Apparently, object constructors aren't composable. Discriminated union constructors don't seem to have this problem:
> 1 + 1 |> Some;;
val it : int option = Some 2
If you want to use the pipeline, Brian's answer is probably best. In this case, I'd consider just wrapping the entire expression with Shape( ).

Resources