Easy way to convert int [,] to int [] [] in F# [duplicate] - f#

This question already has answers here:
F# converting Array2D to array of arrays
(2 answers)
Closed 5 years ago.
We have two arrays
let a = [| [|1|] |]
and
let a' = Array2D.init 1 1 (fun x y -> 1)
the first returns int [][] and the second int [,]
Is there an easy way to convert int[,] to int [][] ?

There are no built-in functions to do this. I would use list comprehension syntax, that would seem straightforward:
let a =
[| for i in 0..(Array2D.length1 a' - 1) ->
[| for j in 0..(Array2D.length2 a' - 1) -> a'.[i,j] |] |]
One thing to look out for is the base index. In your example the array is zero-based, so I used zeroes just to make the code shorter. But if you need to support the case of non-zero-based arrays, you have to do a'.[ i + Array2D.base1 a', j + Array2D.base2 a' ] instead. Not quite as elegant, but watchagonnado.

If it's the building of the array you're interested in, you can build the [][] (aka jagged array) form by using two Array.init
e.g.
Array.init 10 (fun r -> Array.init 20 (fun c -> (c+r)))
[|[|0; 1; 2; 3; 4; 5; 6; 7; 8; 9; 10; 11; 12; 13; 14; 15; 16; 17; 18; 19|];
[|1; 2; 3; 4; 5; 6; 7; 8; 9; 10; 11; 12; 13; 14; 15; 16; 17; 18; 19; 20|];
[|2; 3; 4; 5; 6; 7; 8; 9; 10; 11; 12; 13; 14; 15; 16; 17; 18; 19; 20; 21|];...

Related

Go through a list until some condition is met, in F#

let's take this data:
let a = [10; 11; 12; 13; 14; 0; 15; 16]
I'm trying to do this:
[
let mutable skip = false
for i in 0 .. a.Length - 1 do
if a.[i] = 0 then skip <- true
if not skip then yield a.[i]
]
but I was wondering if List.unfold could be used for this? (and how?)
In practice, I'm getting a sequence of sequences (seq of rows, each holding a seq of columns, from an Excel file), and I want to stop the parsing when I encounter an empty line, but the simplified example illustrates it.
The expression above works, so this is about me learning if unfold could be applied to this.
I would use takeWhile:
let a = [10; 11; 12; 13; 14; 0; 15; 16]
Seq.takeWhile ((<>) 0) a
// |> do your parsing
Yes, you can use List.unfold:
let a = [10; 11; 12; 13; 14; 0; 15; 16]
a
|> List.unfold (function
| [] -> None
| x :: rest -> if x = 0 then None else Some (x, rest)
)

Remove a single element from an array

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|]

How do you extract distinct elements from a list?

I'm pretty new to f# and I'm having a hard time trying to extract a list of distinct values from a list:
let myList = [ 1; 2; 2; 3; 4; 3 ]
// desired list
[ 1; 2; 3; 4 ]
How do I do that? I see that seq has a distinct method, but not lists.
let myList = [ 1; 2; 2; 3; 4; 3 ]
let distinctList = myList |> Seq.distinct |> List.ofSeq
Result:
>
val myList : int list = [1; 2; 2; 3; 4; 3]
val distinctList : int list = [1; 2; 3; 4]
Next F# version (4.0) will have List.distinct function
Not sure if worse or better than Petr answer but you could also do :
let distinct xs = xs |> Set.ofList |> Set.toList
> distinct [ 1; 2; 2; 3; 4; 3 ];;
val it : int list = [1; 2; 3; 4]

Is this the most efficient algorithm to calculate the cross product of two sets of numbers?

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

F# List.Map using a random number

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.

Resources