Assign value to array based on row criteria true/false - f#

Hi i would like to achieve something like
Arr.[(rows where criteria is met),K] <- 1
How do I write this in F#?
I.e I have an array
let x= [|0.0..10.0|]
Arr`s number of rows is equal to x.length and the criteria could be rows where x==10.0, the index 9. Not confined to be only a single index that matches the criteria.
Stig

x |> Array.iteri (fun i x ->
if x = 10.0 then Arr.[i] <- 1)

Related

Recursive function in F# that determines in a list of n elements of type int, the greater of two adjacent values

I have recently started learning f# and I have a problem with a task like the one in the subject line. I managed to solve this task but not using a recursive function. I have tried to convert my function to a recursive function but it does not work because in the function I create arrays which elements I then change. Please advise me how to convert my function to a recursive function or how else to perform this task.
let list = [8;4;3;3;5;9;-7]
let comp (a,b) = if a>b then a elif b = a then a else b
let maks (b: _ list) =
let x = b.Length
if x % 2 = 0 then
let tab = Array.create ((x/2)) 0
for i = 0 to (x/2)-1 do
tab.[i] <- (comp(b.Item(2*i),b.Item(2*i+1)))
let newlist = tab |> Array.toList
newlist
else
let tab = Array.create (((x-1)/2)+1) 0
tab.[(((x-1)/2))] <- b.Item(x-1)
for i = 0 to ((x-1)/2)-1 do
tab.[i] <- (comp(b.Item(2*i),b.Item(2*i+1)))
let newlist = tab |> Array.toList
newlist
It is worth noting that, if you were doing this not for learning purposes, there is a nice way of doing this using the chunkBySize function:
list
|> List.chunkBySize 2
|> List.map (fun l -> comp(l.[0], l.[l.Length-1]))
This splits the list into chunks of size at most 2. For each chunk, you can then compare the first element with the last element and that is the result you wanted.
If this is a homework question, I don't want to give away the answer, so consider this pseudocode solution instead:
If the list contains at least two elements:
Answer a new list consisting of:
The greater of the first two elements, followed by
Recursively applying the function to the rest of the list
Else the list contains less than two elements:
Answer the list unchanged
Hint: F#'s pattern matching ability makes this easy to implement.
Thanks to your guidance I managed to create the following function:
let rec maks2 (b: _ list,newlist: _ list,i:int) =
let x = b.Length
if x >= 2 then
if x % 2 = 0 then
if i < ((x/2)-1)+1 then
let d = (porownaj(b.Item(2*i),b.Item(2*i+1)))
let list2 = d::newlist
maks2(b,list2,i+1)
else
newlist
else
if i < ((x/2)-1)+1 then
let d = (porownaj(b.Item(2*i),b.Item(2*i+1)))
let list2 = d::newlist
maks2(b,list2,i+1)
else
let list3 = b.Item(x-1)::newlist
list3
else
b
The function works correctly, it takes as arguments list, empty list and index.
The only problem is that the returned list is reversed, i.e. values that should be at the end are at the beginning. How to add items to the end of the list?
You can use pattern matching to match and check/extract lists in one step.A typical recursive function, would look like:
let rec adjGreater xs =
match xs with
| [] -> []
| [x] -> [x]
| x::y::rest -> (if x >= y then x else y) :: adjGreater rest
It checks wether the list is empty, has one element, or has two elements and the remaining list in rest.
Then it builds a new list by either using x or y as the first element, and then compute the result of the remaing rest recursivly.
This is not tail-recursive. A tail-call optimized version would be, that instead of using the result of the recursive call. You would create a new list, and pass the computed valuke so far, to the recursive function. Usually this way, you want to create a inner recursive loop function.
As you only can add values to the top of a list, you then need to reverse the result of the recursive function like this:
let adjGreater xs =
let rec loop xs result =
match xs with
| [] -> result
| [x] -> x :: result
| x::y::rest -> loop rest ((if x >= y then x else y) :: result)
List.rev (loop xs [])

What would be an example for Frame.mapCols?

I am trying to create examples for all the methods in Deedle, with mixed success. I was able to provide an example for Frame.filterColValues but not for Frame.mapCols. Stealing from one of Tomas Petricek's numerous writeups, I defined a DataFrame as follows:
open Deedle
let dates =
[ DateTime(2013,1,1);
DateTime(2013,1,4);
DateTime(2013,1,8) ]
let values = [ 10.0; 20.0; 30.0 ]
let first = Series(dates, values)
/// Generate date range from 'first' with 'count' days
let dateRange (first:System.DateTime) count =
seq {for i in 0..(count - 1) -> first.AddDays(float i)}
/// Generate 'count' number of random doubles
let rand count =
let rnd = System.Random()
seq {for i in 0..(count - 1) -> rnd.NextDouble()}
// A series with values for 10 days
let second = Series(dateRange (DateTime(2013,1,1)) 10, rand 10)
// df1 has two columns
let df1 = Frame(["first"; "second"], [first; second])
Next I was able to provide an example for Frame.filterColValues:
let df2 = Frame.filterColValues (fun s -> (s.GetAtAs<double>(0) > 5.0)) df1
// df2 has only one column
Frame.toArray2D(df2)
But I could not (and I tried hard) create an example for Frame.map cols. The best I could come up with was:
let df3 = Frame.mapCols (fun k x -> x.GetAtAs<double>(0)) df1
error FS0001: The type 'double' is not compatible with the type 'ISeries<'a>'
What am I doing wrong? Can someone post an example? Or, even better, point to a place where there are examples for the Deedle methods?
The Frame.mapCols function lets you transform a column series into another column series.
The most basic example is just to return the column series unchanged:
df1
|> Frame.mapCols (fun k col -> col)
As Foggy Finder mentioned in a comment, you can fill all missing values in a column using this - the body of the lambda has to return a series:
df1
|> Frame.mapCols (fun k v -> Series.fillMissingWith 0.0 v)
If you wanted, you could return a series with just a single element (this turns your frame into a frame with one row - containing data from the first row - and original number of columns):
df1
|> Frame.mapCols (fun k col -> series [ 0 => col.GetAtAs<float>(0) ])
In your code snippet, it looks like you wanted just a series (with a single value for each column), which can be done by getting the columns and then using Series.map:
df1.Columns
|> Series.map (fun k col -> col.GetAtAs<float>(0))

How do I get the max value from a list with a function that takes two arguments?

Define the function max2 that takes two integers as arguments and returns the largest of them.
I did this: let max2 x y = if x < y then y else x this I belive is correct
Then define the function max_list that returns the largest of the elements in a nonempty list of integers by calling max2. For the empty list, it should abort with an error message ( raising an exception)
I did this: let list = [3;4] let max_list = if list.IsEmpty then 0 else max2 list.Item(0) list.Item(1) but this wont work if the list is more then two elements. I dont want to use any object-orientated stuff. What is the correct answer?
The correct answer is that you should read about recursion with lists.
F# list is built up gradually using empty list [] and cons (::) constructor. For example,
[3; 4] is a syntactic sugar for 3::4::[]. We often use pattern matching on lists in writing recursive functions.
Here is a recursive function following your requirements closely:
let rec max_list xs =
match xs with
// The function aborts with an error message on empty lists
| [] -> invalidArg "xs" "Empty list"
// Return immediately on a singleton list
| [x] -> x
// xs has at least two elements, call max_list
// on the bigger element of the first two ones and the rest of the list
| x1::x2::xs' -> max_list((max2 x1 x2)::xs')
On a side note, there is a built-in generic max function which also works on integers.
A simple recursive solution:
let max2 x y = if x < y then y else x
let max_list list =
let rec loop hi list =
match list with
| h::t -> let hi = max2 h hi
loop hi t
| [] -> hi
match list with
| h::t -> loop h t
| [] -> invalidArg "list" "Empty list"
Test in FSI:
> max_list [3;4;5;1;2;9;0];;
val it : int = 9
For each element in the list, compare it to the previous highest ('hi'). Pass the new highest and the rest of the list into the loop function, until the input list is empty. Then just return 'hi'.

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

How to use filter like if then else statement on a list?

i would like to add 1 items to a list which has only one item and add items(after using toInt to convert to integer) in a list y if number of items greater than 1 and the last items are the same
How to do?
import Data.List.Split
z = splitOn "+" "x^2+2*x^3+x^2"
y = map (splitOn "*") z
x = map head y
toInt :: [String] -> [Int]
toInt = map read
u = filter ((map length y)>1) y
Couldn't match expected type `a0 -> Bool' with actual type `Bool'
In the first argument of `filter', namely `((map length y) > 1)'
In the expression: filter ((map length y) > 1) y
In an equation for `u': u = filter ((map length y) > 1) y
Failed, modules loaded: none.
Your definition of u is obviously bad. It helps if you give type signatures, so we understand a little better what you are trying to do (even when you don't tell us in words).
You commented that you want all lists of length > 1, this is the same as getting all non-null lists after dropping the first element. So use filter, which tests each element separately (so you don't need map), and build a function that either tests a single list for length > 1 or it's sublist for null:
-- Use the O(n) length for your filter
u = filter ((> 1) . length) y
-- Or use an O(1) drop + null test
u' = filter (not . null . drop 1) y
Without using function composition (.) these functions are:
u = filter (\sublist -> length (sublist) > 1) y
u' = filter (\sublist -> not (null (drop 1 sublist))) y
The compiler is telling you that map length y > 1 is a boolean value, but filter wants a function there. I am not sure what you really want do to with y, please specify what you expect for different values of y.

Resources