Array of arrays in F# - f#

I have the following array CF which contains arrays. How can I set up another array of same length as CF which finds the nth element of arrays within CF.
let CF= [|for i in 0..(Connection.Length-1)->
res RProject.[i] rc.[i] D.[i] in.[i]|]

If I understand the question correctly, you want the nth element of each array, mapped to a new array. You can do this with Array.map.
Here's an example. First, an array of arrays:
let a1 = [| [|1; 2; 3|]; [| 4; 5; 6 |] |]
Let's say you want the second element in each of these arrays, mapped into a new array. This can be done like this:
let a2 = a1 |> Array.map (fun a -> [| a.[1] |])
In this example, a2 will now have the value [|[|2|]; [|5|]|].
Notice that an exception will be thrown if you attempt to access an array index that is outside the bounds of any of the arrays.

Related

Write Array with List to csv

I have an array with multiple lists inside and want to write the values to an CSV
unfortunately I cannot figure out how to write the Array.mapi.
Any ideas?
let temp = [|title;body;ordinariePris;extraPris;inkopPris;images;allValues|]
let lines2 =
temp
|> Array.mapi (fun idx (t,b,op,ep,ip,i,av) ->
sprintf "%s\t%s\t%s\t%s\t%s\t%s\t%s\t%s" title body ordinariePris extraPris inkopPris images allValues
)
let header = "title\tbody\tordinariePris\textraPris\tinkopPris\tallValues"
System.IO.File.WriteAllLines("test.csv",
Array.append [| header|]lines2, Encoding.UTF8)
thanks in advance
The problem with your code is that mapi indexes over the elements of temp, which means that you're only getting one column at a time. You want to retrieve one row at a time.
The following instead transposes your list of lists, so that indexing does what you want. It's also a little more generic-- you don't actually need to know the number of columns ahead of time. It does, however, assume that every column has the same number of elements in it.
let col1 = ["a"; "b"; "c"]
let col2 = ["1"; "2"; "3"]
let col3 = ["x"; "y"; "z"]
let cols = [col1; col2; col3]
let transpose(xs: string list list) : string list list =
[0 .. xs.[0].Length - 1] |> List.map (fun i ->
xs |> List.rev |> List.fold (fun acc col -> col.[i] :: acc) []
)
let stringify_rows(xs: string list list) : string list =
xs |> List.map (fun row -> System.String.Join(",", row))
System.IO.File.WriteAllLines("test.csv", cols |> transpose |> stringify_rows)
Note that this approach does not use an array of lists, since there was no obvious reason that you had to use an array. WriteAllLines will happily accept any IEnumerable.
If you do a lot of CSV writing, I recommend using a library like CsvHelper, since correctly handling when to quote or escape cell contents can be tricky.

plotting an array on F#, how to index axis by year

I would like to create create a graph of an array on F sharp as follows:
let compperformance= Array.zip firstarray secondarray |> Array.map (fun (a,b)
-> (b-a))
Chart.Line(compperformance, Title="dy").WithXAxis(Title="year", Min=1.0, Max=39.0)
.WithYAxis(Title="Cumulative SSE difference")
How can I change the x-axis to year (min=1960.0 to max=2000.0)? When I define min and max as such, the graph disappears. Let me know.
You can pass a sequence of key value pairs to Chart.Line:
let compperformance=
Array.zip firstarray secondarray |> Array.map (fun (a,b) -> (b-a))
let dataWithYears =
Array.zip [| 1960 .. 2000 |] compperformance
Chart.Line(dataWithYears, Title="dy")
.WithXAxis(Title="year", Min=1.0, Max=39.0)
.WithYAxis(Title="Cumulative SSE difference")
This assumes that there is exactly 41 values in compperformance, which might not quite work - you may need to do this a bit differently - but it shows the idea - just produce an array containing year, value tuples.

Retrieve array of tuples with different number of elements in F#

I have the following demand: getting the array of tuples from the first array according to the elements’ appearance in the second array:
let totals = [| ("old1", "new1"); ("old2", "new2"); ("old3", "new3"); ("old4", "new4") |]
let changes = [| "new1"; "new4" |]
I want to have this:
let updates = [| ("old1", "new1"); ("old4", "new4") |]
If the both arrays totals and changes have the same length, then I think it is easy:
let updates = Array.zip changes totals
|> Array.choose(fun (a, B) -> if a = fst(B) then Some (B) else None)
Unfortunately, totals and changes have different number of elements; therefore, I can not find an easy way to get the elements I need.
The solution posted by pad is correct and will work fine for small number of elements in changes. However, it iterates over the array changes for every element in total, so it may be inefficient for large arrays.
As an alternative, you can turn changes into an F# set type which allows more efficient membership test:
// Create set containing 'changes'
let changesSet = Set.ofArray changes
// Filter totals where the second element is in 'changesSet'
totals |> Array.filter (fun (_, v) -> changesSet.Contains(v))
// Same thing using function composition
totals |> Array.filter (snd >> changesSet.Contains)
You should select pairs in totals which have second elements occur in changes:
let updates =
totals
|> Array.filter (fun (_, x) -> changes |> Array.exists (fun y -> y = x))

F# how to append/join array2D and combine 1D arrays to array2D

in F#, array.append can join two arrays; is there a way to append 2 array2D objects into one or column-wise join several 1-D arrays into one array2D object?
The array2D function will turn any seq<#seq<'T>> into a 'T [,] so it should work for turning a bunch of 1D arrays into a 2D array.
let arr1 = [| 1; 2; 3 |]
let arr2 = [| 4; 5; 6 |]
let combined = array2D [| arr1; arr2 |]
As far as I can see, there is no F# library function that would turn several 1D arrays into a single 2D array, but you can write your own function using Array2D.init:
let joinInto2D (arrays:_[][]) =
Array2D.init arrays.Length (arrays.[0].Length) (fun i j ->
arrays.[i].[j])
It takes an array of arrays, so when you call it, you'll give it an array containing all the arrays you want to join (e.g. [| arr1; arr2 |] to join two arrays). The function concatenates multiple 1D arrays into a single 2D array that contains one row for each input array. It assumes that the length of all the given arrays is the same (it may be a good idea to add a check to verify that, for example using Array.forall). The init function creates an array of the specified dimensions and then calls our lambda function to calculate a value for each element - in the lambda function, we use the row as an index in the array of arrays and the column as an index into the individual array.
Here is an example showing how to use the function:
> let arr1 = [| 1; 2; 3 |]
let arr2 = [| 4; 5; 6 |];;
> joinInto2D [| arr1; arr2 |];;
val it : int [,] = [[1; 2; 3]
[4; 5; 6]]
EDIT: There is already a function to do that - nice! I'll leave the answer here, because it may still be useful, for example if you wanted to join 1D arrays as columns (instead of rows, which is the behavior implemented by array2D.
I don't think there's anything built-in to handle this. You can define your own reusable method based on either Array2D.init or Array2D.blit, though. If you need to combine several columns into one logical whole, I think it would frequently be more convenient to use an array of arrays rather than a 2D array (and in general, the 1D array operations in .NET are significantly faster than the multi-dimensional array operations).

F# slicing array by indices array

How can I overload .[] for F# array to slice an array based on an arbitrary index array?
For example:
let x = [|1..10|];
let indx = [|4;1|];
although
[| for i in indx ->x.[i]|]
would work, it would be nicer to be able using x.[indx] directly.
You can always write an F# extension method to get close on the syntax
let a = [| 1..10 |]
let idx = [|4;1|]
type 'T ``[]`` with //'
member this.Slice(indices:int array) =
[| for i in indices -> this.[i] |]
printfn "%A" (a.Slice idx)
but since arrays already have an indexer it doesn't appear there's a way to overload/change it.

Resources