Implement a matrix with another matrix in F# - f#

I have the first matrix which should account for each users (in lines) which products (in columns) they like.
Let's take 3 users and 5 products.
No user liked a product, so my matrix ILike equals a nul matrix :
let matrixILike = [[0.; 1.;2.;3.]
[1.;0.;0.;0.]
[2.;0.;0.;0.]
[3.;0.;0.;0.]
[4.;0.;0.;0.]
[5.;0.;0.;0.]]
Now user 1 likes product 2 and user 3 likes product 5 which can be summarized in the following matrix:
let matrixAction = [[1.;2.]
[3.;5.]]
So I would like to implement the matrix ILike thanks to the matrixAction to obtain a new updated matrixILike like this :
let matrixILike = [[0.; 1.;2.;3.]
[1.;0.;0.;0.]
[2.;1.;0.;0.]
[3.;0.;0.;0.]
[4.;0.;0.;0.]
[5.;0.;0.;1.]]
I try to do this with a "match with" code but it is not working.
for k = 0 to matrixAction.NumRows - 1 do
match (matrixAction.[k,0] , matrixAction.[k,1]) with
| (matrixILike.[x,0] , matrixILike.[0,y]) -> (matrixILike.[x,y] <- 1.)
| _ -> (matrixILike.[x,y] <- 0.)
matrixILike
If you have any suggestions I take it.

This is trivial if you change matrixILike to an array.
let matrixILike = [|
[|0.;1.;2.;3.|]
[|1.;0.;0.;0.|]
[|2.;0.;0.;0.|]
[|3.;0.;0.;0.|]
[|4.;0.;0.;0.|]
[|5.;0.;0.;0.|]
|]
let matrixAction = [
(1., 2.)
(3., 5.)
]
matrixAction
|> List.iter (fun (u, p) -> matrixILike.[int p].[int u] <- 1.)

Without changing your input parameters, this function will do the job.
let update actions =
let mapiTail f = function
| [] -> []
| h::t -> h :: List.mapi (f h) t
mapiTail (fun matHead _ ->
mapiTail (fun rowHead i x ->
if List.exists ((=) [matHead.[i+1];rowHead]) actions then 1. else x))
Usage:
update matrixAction matrixILike
It uses List.mapi which is the same as List.map but with additional parameter: the index.

Related

F# : filtering None out and keeping only Some

A quick question on how to effectively group/filter list/seq.
Filter for only records where the optional field is not None
Remove the "option" parameter to make future processes easier (as None has been filtered out)
Group (this is of no problem I believe)
Am I using the best approach?
Thanks!
type tmp = {
A : string
B : int option }
type tmp2 = {
A : string
B : int }
let inline getOrElse (dft: 'a) (x: 'a option) =
match x with
| Some v -> v
| _ -> dft
let getGrouped (l: tmp list) =
l |> List.filter (fun a -> a.B.IsSome)
|> List.map (fun a -> {A = a.A ; B = (getOrElse 0 (a.B)) })
|> List.groupBy (fun a -> a.A)
The most natural approach for map+filter when option is involved is to use choose, which combines those two operations and drops the option wrapper from the filtered output.
Your example would look something like this:
let getGrouped (l: tmp list) =
l
|> List.choose (fun a ->
a.B
|> Option.map (fun b -> {A = a.A; B = b})
|> List.groupBy (fun a -> a.A)
The simple solution is just use the property that an option can be transformed to list with one or zero elements then you can define a function like:
let t1 ({A=a; B=b} : tmp) =
match b with
| (Some i) -> [{ A = a; B= i}]
| _ -> []
let getGrouped (l: tmp list) =
l |> List.collect t1
|> List.groupBy (fun a -> a.A)

Subtract two Maps of Map<'a, int>

I have the following type:
type Multiset<'a when 'a: comparison> = MSet of Map<'a, int>
I want to declare a function for this type that subtracts two MSets.
Let's say I have the following two Multisets:
let f = MSet (Map.ofList [("a",1);("b",2);("c",1)])
let g = MSet (Map.ofList [("a",1);("b",3);("c",1)])
I have now tried to create this subtract function which takes two Multisets.
let subtract fms sms =
match fms with
| MSet fs -> match sms with
| MSet ss ->
let toList ms = Map.fold (fun keys key value -> keys # [for i = 1 to value do yield key] ) [] ms
let fromList l = match l with
| [] -> MSet(Map.ofList [])
| x::xs -> MSet(Map.ofList (x::xs |> Seq.countBy id |> Seq.toList))
let sfList = toList fs
let ssList = toList ss
fromList (List.filter (fun n -> not (List.contains n sfList)) ssList)
If I run :
subtract f g
It returns :
MSet (map [])
Which is not what I wanted. g contains one more b than f, so I would want it to return:
MSet(map [("b", 1)])
My implementation doesn't account for multiple occurrences of the same key. I am not quite sure how I can fix this, so I get the wanted functionality?
I suspect you just have your arguments reversed, that's all. Try subtract g f.
That said, your solution seems way more complicated than it needs to be. How about just updating the values in the first map by subtracting the counts in the second, then removing non-positive counts?
let sub (MSet a) (MSet b) =
let bCount key = match Map.tryFind key b with | Some c -> c | None -> 0
let positiveCounts, _ =
a
|> Map.map (fun key value -> value - (bCount key))
|> Map.partition (fun _ value -> value > 0)
MSet positiveCounts
Also, the nested match in your implementation doesn't need to be there. If you wanted to match on both arguments, you can just do:
match fms, sms with
| MSet fs, MSet ss -> ...
But even that is an overkill - you can just include the pattern in parameter declarations, like in my implementation above.
As for duplicate keys - in this case, there is no reason to worry: neither of the arguments can have duplicate keys (because they're both Maps), and the algorithm will never produce any.
The underlying issue, also evident in your other question, seems to be the unification of identical keys. This requires an equality constraint and can be easily effected by the high-level function Seq.groupBy. Since comparison isn't strictly necessary, I propose using a dictionary, but the approach would work also with maps.
Given a type
type MultiSet<'T> = MultiSet of System.Collections.Generic.IDictionary<'T, int>
and a helper which maps the keys, sums their values and validates the result;
let internal mapSum f =
Seq.groupBy (fun (KeyValue(k, _)) -> f k)
>> Seq.map (fun (k, kvs) -> k, Seq.sumBy (fun (KeyValue(_, v)) -> v) kvs)
>> Seq.filter (fun (_, v) -> v > 0)
>> dict
>> MultiSet
your operations become:
let map f (MultiSet s) =
mapSum f s
let add (MultiSet fms) (MultiSet sms) =
Seq.append fms sms
|> mapSum id
let subtract (MultiSet fms) (MultiSet sms) =
Seq.map (fun (KeyValue(k, v)) ->
System.Collections.Generic.KeyValuePair(k, -v)) sms
|> Seq.append fms
|> mapSum id
let f = MultiSet(dict["a", 1; "b", 2; "c", 1])
let g = MultiSet(dict["a", 1; "b", 3; "c", 1])
subtract f g
// val it : MultiSet<string> = MultiSet (seq [])
subtract g f
// val it : MultiSet<string> = MultiSet (seq [[b, 1] {Key = "b";
// Value = 1;}])

Matrix transposition in F#

I'm trying to modify a matrix like this one:
/ 1 2 3 \
\ 4 5 6 /
to return:
/ 1 4 \
| 2 5 |
\ 3 6 /
Instead it is flipping my matrix by the corners. This is the code I have so far:
Let rec matrixadjust = function
| (_::_) : : as xss-> List.map List.head xss :: matrixadjust (List.map List.tail xss)
| _ ->[];;
I think that the best way to work with matrix is using the Array2D data structure. You can build an Array2D from an array of arrays and then create a new Array2D to acomplish what you want:
let arrayOfArrays = [| [| 1; 2; 3 |]; [|4; 5; 6 |] |]
let array2d = Array2D.init 2 3 (fun row column -> arrayOfArrays.[row].[column])
let newArray = Array2D.init (array2d |> Array2D.length2) (array2d |> Array2D.length1) (fun r c -> array2d.[c,r])
Assuming your data structure is a list of lists where each sub-list represents a row you could do it like this. Basically it loops once per source-list row and accumulates the result in the partial binding. Since its doing list accumulation, it reverses the order of the values so you have to do a List.rev on each row at the end.
let flip matrix =
match matrix with
| [] -> []
| x::xs ->
let rec loop matrix partial =
match matrix with
| [] -> partial
| y::ys ->let newPartial = (y, partial) ||> List.map2(fun x y->x::y)
loop ys newPartial
let length = List.length x
loop matrix (List.init length (fun _ -> [] ))
|> List.map(fun x->x |> List.rev)

Swapping every pair of items in an F# list

I'm positive that there is a better way to swap items in a list by pairs ( [1;2;3;4] -> [2;1;4;3] ) as I'm doing too many appends for my liking but I'm not sure how best to do it.
let swapItems lst =
let f acc item =
match acc with
| [] -> [item]
| hd :: next :: tl when tl <> [] -> [next] # tl # [item;hd]
| _ -> item :: acc
List.fold f [] lst
How can I improve this? This only works on lists that have an even length.
Simplest possible solution:
let rec swapItems = function
| a::b::xs -> b::a::swapItems xs
| xs -> xs
I like to make the names of variables that are sequences like lists "plural", e.g. xs instead of x.
Note that this is not tail recursive so it will stack overflow if you give it a very long list.
What about this:
let rec swapItems = function
| []
| _::[] as l -> l
| a::b::t ->
b::a::(swapItems t)
?
Using higher order functions this can be done as:
let swapItems l =
l |> List.toSeq |> Seq.pairwise
|> Seq.mapi (fun i (a,b) -> if i % 2 = 0 then seq [b;a] else Seq.empty)
|> Seq.concat |> Seq.toList

How to find the value in a list at which a maximum value of a function occurs

I want to find not just the maximum value of a function applied to a list (for which I would just use List.maxBy) but also the value in the list this occurred at. This feels like a fairly common operation and given the richness of the F# libraries in general I wouldn't be at all surprised to discover it was actually already available but I cannot seem to find it if it is!
To illustrate with an example, I want to be able to map a list domain and a function f
let domain = [0 .. 5]
let f x = -x * (x - 2)
to (1, 1) (since the function applied to an other element of the list is less than 1).
I first tried this:
let findMaximum domain f =
let candidates = [ for x in domain do
yield x, f x ]
let rec findMaximumHelper domain f currentMax =
match domain with
| [] -> currentMax
| head::tail ->
let cand = f head
match currentMax with
| None ->
let newMax = Some(head, cand)
findMaximumHelper tail f newMax
| Some(maxAt, possMax) ->
let newMax =
if cand > possMax then Some(head, cand)
else Some(maxAt, possMax)
findMaximumHelper tail f newMax
findMaximumHelper domain f None
let answer = findMaximum domain f
at which point I realised this is very close to a fold operation, and put together
let findMaximum2 domain f =
let findMaximumHelper f acc x =
let cand = f x
match acc with
| None -> Some(x, cand)
| Some(maxAt, possMax) ->
if cand > possMax then Some(x, cand)
else Some(maxAt, possMax)
List.fold (findMaximumHelper f) None domain
let answer2 = findMaximum2 domain f
instead.
My question is, are these idiomatic F# ways of solving this problem, or indeed, is there a better way of solving this?
Indeed, the F# library provides all the necessary higher order functions to express this succinctly:
domain
|> Seq.map (fun x -> x, f x)
|> Seq.maxBy snd
Note: updated to use Seq.map and Seq.maxBy instead of List.map and List.maxBy to address #ildjarn's concern about creating an unnecessary intermediate list.
An alternative to Stephen's answer, that avoids creating a second List, with the tradeoff of executing f one extra time:
domain
|> List.maxBy f
|> fun x -> x, f x

Resources