I am trying to apply a function to two arrays of different lengths but the result is not matching my expectations. I need to reuse elements of the second array (similar to R) to complete the expression:
module SOQN =
open System
let first = [|2; 3; 5; 7; 11|]
let second = [|13; 17; 19|]
let result =
[for i in [0..first.Length-1] do
for j in [0..second.Length-1] do
yield (first.[i] * second.[j])]
printfn "Result: %A" result
// Actual Result: [|26; 34; 38; 39; 51; 57; 65; 85; 95; 91; 119; 133; 143; 187; 209|]
// Expected Result: [|26; 51; 95; 91; 187|]
What am I missing?
I guess you looking for something like this
let result =
Array.mapi
(fun i v -> second.[i % second.Length] * v) first
Here is another way of doing it:
let first = [|2; 3; 5; 7; 11|]
let second = [|13; 17; 19|]
let map2Cycle (x: 'T []) (y: 'T []) (f: 'T -> 'T -> 'S) =
let lenx = Array.length x
let leny = Array.length y
let xInf = Seq.initInfinite (fun _ -> x) |> Seq.concat
let yInf = Seq.initInfinite (fun _ -> y) |> Seq.concat
Seq.map2 f xInf yInf
|> Seq.take (max lenx leny)
|> Array.ofSeq
map2Cycle first second (*)
// val it : int [] = [|26; 51; 95; 91; 187|]
And here is a slightly different one:
let map2Cycle' (x: 'T []) (y: 'T []) (f: 'T -> 'T -> 'S) =
let lenx = Array.length x
let leny = Array.length y
let (x', y') =
if lenx >= leny then x |> Seq.ofArray, Seq.initInfinite (fun _ -> y) |> Seq.concat
else Seq.initInfinite (fun _ -> x) |> Seq.concat, y |> Seq.ofArray
Seq.map2 f x' y'
|> Seq.take (max lenx leny)
|> Array.ofSeq
map2Cycle' first second (*)
// val it : int [] = [|26; 51; 95; 91; 187|]
Related
I need to map the values in tmp to labels in tmpRplcd based on comparison with percentiles in prcntls, but the Array.map2 line fails because the arrays are of different lengths.
module SOQN =
open System
open MathNet.Numerics.Statistics
let tmp = [| 13.0; 17.0; 23.0; 11.0; 11.0; 13.0; 31.0;
19.0; 47.0; 29.0; 29.0; 19.0; 43.0; 37.0 |]
let tmpPrcntls =
tmp
|> Array.sort
let lbls = [| "p0"; "p1"; "p2"; "p3"; "p4";"p5" |]
let prcntls = [| Statistics.Percentile(tmpPrcntls,0) // 11.0
Statistics.Percentile(tmpPrcntls,20) // 13.0
Statistics.Percentile(tmpPrcntls,40) // 19.0
Statistics.Percentile(tmpPrcntls,60) // 28.6
Statistics.Percentile(tmpPrcntls,80) // 35.8
Statistics.Percentile(tmpPrcntls,100) // 47.0
|]
let lkpTbl = Map(Array.zip prcntls lbls)
let tmpRplcd:string[] =
tmp
|> Array.map2 (fun x y -> if x <= y then lkpTbl.[y] else "") prcntls
let main =
printfn ""
printfn "Percentile Test"
printfn ""
printfn "tmpPrcntls: %A" tmpPrcntls
printfn "prcntls:%A" prcntls
printfn "tmpRplcd:%A" tmpRplcd
0
[<EntryPoint>]
main
|> ignore
// Expected Result:
// tmpRplcd = [| "p1"; "p2"; "p3"; "p0"; "p0"; "p1"; "p4";
// "p2"; "p5"; "p4"; "p4"; "p2"; "p5"; "p5" |]
Where am I going wrong?
I think your use of map2 is wrong - the map2 function zips the two arrays and then applies the given function to the zipped array.
Based on your question, my guess is that you actually want to do something else. For every input, you want to iterate over all percentiles and find the first percentile such that the value is greater (or smaller?) than the percentile. To do this, you need to replace map2 with something like this:
let tmpRplcd:string[] =
tmp
|> Array.map (fun y ->
prcntls |> Array.tryPick (fun x ->
if x <= y then Some(lkpTbl.[x]) else None))
|> Array.map (fun v -> defaultArg v "")
I don't have the right version to try this, but I think this should do what you need (I'm just not sure if you need x <= y or the other way round!)
Here follows an approach to what you'd intend to do with your F# program.
I came up with an implementation of the percentile calculation from http://www.dummies.com/education/math/statistics/how-to-calculate-percentiles-in-statistics/ , which is shown in the Statistics module below.
namespace FSharpBasics
module Statistics =
let percentile p (array: float[]) =
let threshold = (float p / 100.0) * float (array |> Array.length)
let thresholdCeiling = int (System.Math.Ceiling threshold)
let thresholdInteger = int (threshold)
array
|> Array.sort
|> Array.skip (thresholdCeiling - 1)
|> Array.truncate (if thresholdInteger = thresholdCeiling then 2 else 1)
|> Array.average
module PercentileTest =
open System
let tmp = [| 13.0; 17.0; 23.0; 11.0; 11.0; 13.0; 31.0;
19.0; 47.0; 29.0; 29.0; 19.0; 43.0; 37.0 |]
let lbls =
[| for n in 0..20..100 -> "p" + string (n / 20) |]
let prcntls =
[| for n in 0..20..100 -> Statistics.percentile n tmp |]
let tmpPrcntls =
tmp |> Array.sort
let lkpTbl =
Array.zip prcntls lbls
let tmpRplcd : string[] =
tmp
|> Array.map (fun x ->
lkpTbl
|> Array.filter (fun (prcntl, lbl) -> prcntl <= x)
|> Array.last
|> snd)
[<EntryPoint>]
let main argv =
printfn ""
printfn "Percentile Test"
printfn ""
printfn "tmp: %A" tmp
printfn "tmpPrcntls: %A" tmpPrcntls
printfn "prcntls: %A" prcntls
printfn "tmpRplcd: %A" tmpRplcd
System.Console.ReadKey() |> ignore
0 // return an integer exit code
(*---- output ----
Percentile Test
tmp: [|13.0; 17.0; 23.0; 11.0; 11.0; 13.0; 31.0; 19.0; 47.0; 29.0; 29.0; 19.0; 43.0;
37.0|]
tmpPrcntls: [|11.0; 11.0; 13.0; 13.0; 17.0; 19.0; 19.0; 23.0; 29.0; 29.0; 31.0; 37.0; 43.0;
47.0|]
prcntls: [|11.0; 13.0; 19.0; 29.0; 37.0; 47.0|]
tmpRplcd: [|"p1"; "p1"; "p2"; "p0"; "p0"; "p1"; "p3"; "p2"; "p5"; "p3"; "p3"; "p2"; "p4";
"p4"|]
---- ----*)
I am trying to calculate covariance matrix
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
CovMatrix.[a,b]
How to fix this and why it happens?
let FirstSeq = {1.0..10.0}
let SecondSeq = {20.0..30.0}
let All = seq {yield (0,FirstSeq); yield (1,SecondSeq)}
let cov(first:seq<float>)(second:seq<float>) =
Seq.map2 (*) first second
|> Seq.average
|> fun x -> x - Seq.average first * Seq.average second
let CreateCovMatrix(strangeList:seq<int * seq<float>>) =
let Size = Seq.length strangeList
let CovMatrix = Array2D.init Size Size
let CalculateCovMatrix =
for (a, i) in strangeList do
for (b, j) in strangeList do
CovMatrix.[a,b]=cov(i)(j)
CalculateCovMatrix
let result = CreateCovMatrix(All)
printf "%A" result
The function Array2D.init takes 3 parameters, you're missing the last one, which is the initialization function.
You can quick-fix it by writing:
let CovMatrix = Array2D.init Size Size (fun _ _ -> 0.)
Then you'll discover the next problem: assignment for mutable references is the <- operator, not = which is for comparison and let bindings.
So your function will look like this:
let CreateCovMatrix(strangeList:seq<int * seq<float>>) =
let Size = Seq.length strangeList
let CovMatrix = Array2D.init Size Size (fun _ _ -> 0.)
let CalculateCovMatrix =
for (a, i) in strangeList do
for (b, j) in strangeList do
CovMatrix.[a,b] <- cov(i)(j)
CalculateCovMatrix
But instead of specifying a function that ignores the inputs and return always zero, you can use the function Array2D.zeroCreate :
let CovMatrix = Array2D.zeroCreate Size Size
This kind of math is where functional programming excels,
although you're currently residing in the imperative paradigm. Gustavo handled your warnings, but even so your function won't give the desired result. Mixing functional and imperative concepts CreateCovMatrix now returns unit.
Good imperative:
let createCovMatrix(strangeList:seq<int * seq<float>>) =
let size = Seq.length strangeList
let covMatrix = Array2D.zeroCreate size size
for (a, i) in strangeList do
for (b, j) in strangeList do
covMatrix.[a,b]<-cov(i)(j)
covMatrix
Going functional:
let createCovMatrix strangeList =
strangeList
|> Seq.map (fun (a, i) -> Seq.map (fun (b, j) -> cov i j) strangeList)
|> array2D
Multi functional:
let createCovMatrix strangeList =
let mapper f = Seq.map f strangeList
mapper (fun (a, i) -> mapper (fun (b, j) -> cov i j))
|> array2D
Here is the problem I can't get around, I'm working in ocaml to copy the elements of an array to a new array. I want to be able to modify these arrays independently from each other, but no matter what I try, a change to one array is reflected in the other array as well.
Here is a simplified example:
type sampleType = { a : int; b : int array };;
let x = {a = 5; b = [|1, 2, 3|] };;
let y = x.b;;
Array.set y 1 6;;
After running these commands I want:
y - : int array = [|1; 6; 3|]
x - : sampleType = {a = 5; b = [|1; 2; 3|]}
Instead x is being changed along with y, and
x - : sampleType = {a = 5; b = [|1; 6; 3|]}
Any solutions to this problem?
As you see from your experiments, this code:
let y = x.b
makes y refer to the very same array as x.b. It doesn't create an independent array. To create an independent array, you need to copy:
let y = Array.copy x.b
I was specifically using 3d arrays, realized I had to apply Array.copy at the lowest level of the 3d array, rather than at the top level.
let arr = Array.init 3 (fun _ -> Array.init 3 (fun _ -> (Array.init 3 (fun _ -> {faces = [|0;1;2;3;4|]}))));;
let drr = Array.init 3 (fun i -> Array.init 3 (fun j -> Array.copy arr.(i).(j)));;
This gave me the result I needed.
`So, I am very new to F#. I hope the issue is simple. I have been doing research and looking around. I have an "Incomplete structured construct at or before this point in expression" error. I feel like it might be something simple or I am way off.
The objective is:
There is an array of non negative integers. A second array is
formed by shuffling the elements of the first
array and deleting a random element. Given these two arrays, find which element is missing in the second
array. Linear searching is not allowed.
let FindMiss list =
match list with
| [] ->
[]
|firstElem::otherElements ->
let rand = new Random
let shuffle (arr : 'a array) =
let array = Array.copy arr
let n = array.Length
for x in 1..n do
let i = n-x
let j = rand.Next(i+1)
let tmp = array.[i]
array.[i] <- array.[j]
array.[j] <- tmp
array
return array
array.[rand].delete
|array::list ->
let d=collections.defaultdict(int)
for num in list do
d[num] +=1
for num in array1 do
if d[num]==0 then return num
else d[num]-=1
printfn "The missing Number is: %A" (FindMiss[4;2;1;7;5;6;3;2])
The task is to reimplement List.except?
If not, just use that 'except' then:
[1;2;3] |> List.except [1;2]
Or was the task "random removal of element in list"? Then this is "the answer": https://stackoverflow.com/a/2889972/5514938
For a start, for more readability, you can take the shuffling and deleting a random element in a separate function. For arrays, they may look like this:
let Shuffle arr =
let rand = System.Random()
arr |> Array.sortBy(fun _ -> rand.Next())
let RemoveRandom arr =
let rand = System.Random()
let lng = arr |> Array.length
let index = rand.Next lng
[|0..lng - 1 |]
|> Array.choose(fun x -> if x = index then None else Some(arr.[x]))
|> Shuffle
Further define the search function:
let FindMiss arr1 arr2 =
let sum1 = arr1 |> Array.sum
let sum2 = arr2 |> Array.sum
sum1 - sum2
Example:
let first = [| 4;2;1;7;5;6;3;2 |]
first |> printfn "%A"
let second = first |> RemoveRandom
second |> printfn "%A"
FindMiss first second |> printfn "Missing value is %i"
Print:
[|4; 2; 1; 7; 5; 6; 3; 2|]
[|2; 2; 3; 7; 1; 5; 6|]
Missing value is 4
Link:
https://dotnetfiddle.net/g6wKUX
Let's say that I want to do some in-array comparison in F#, e.g. determine whether a given integer array arr contains integers in strictly increasing order. I would do it like this:
let arri =
arr
|> Array.mapi (fun i e -> i, e)
let isArrStrictlyIncreasing =
arri
|> Array.tryFind (fun e ->
if fst e = arri.Length - 1 then
false
else
snd e >= snd arri.[1 + fst e])
|> Option.isNone
However, I am wondering if there is a more concise, "functional" way of making such in-array comparisons without the use of Array.mapi and if-else?
One simple way:
let isincr arr =
arr
|> Array.fold (fun (a,b) (c) -> ((b<c && a)),c) (true,System.Int32.MinValue)
|> fst
Couldn't you just do the following?
let expected = [| candidate.[0] .. candidate.[0] + candidate.Length - 1 |]
candidate = expected
This simply builds the array you'd expect, and uses F#'s Structural Equality to compare the two arrays.
A more general alternative might be this:
let isOrdered arr = arr |> Array.sort = arr
let hasDistinctMembers (arr : 'a array) =
let distinct = arr |> Seq.distinct |> Seq.toArray
distinct.Length = arr.Length
let isStrictlyIncreasing arr = arr |> isOrdered && arr |> hasDistinctMembers
Usage:
> isStrictlyIncreasing [| 7; 11; 8 |];;
val it : bool = false
> isStrictlyIncreasing [| 7..33 |];;
val it : bool = true
> isStrictlyIncreasing [| 7; 8; 11 |];;
val it : bool = true
> isStrictlyIncreasing [| 7; 7; 8; 11 |];;
val it : bool = false