How can I generate a dictionary from a list? - f#

How can I generate a dictionary from a list?
Take the following list:
let numbers = [1;2;2;3;3;3;4;5;5;]
How can I generate a dictionary where the key is the element and the value is the number of times that the element occurs within the list?
My sad attempt:
let numbers = [1;2;2;3;3;3;4;5;5;]
numbers |> Seq.fold (fun accumulator element -> Map.add (element, element list???) 0)

Use Seq.groupBy
let numbers = [1;2;2;3;3;3;4;5;5]
let map = numbers |> Seq.groupBy id |> Map.ofSeq
map |> Map.iter (printfn "%A - %A")
Print:
1 - seq [1]
2 - seq [2; 2]
3 - seq [3; 3; 3]
4 - seq [4]
5 - seq [5; 5]
Link:
https://dotnetfiddle.net/xyNyzn
Edit:
If you want to get : number - frequency (now using Seq.fold :))
let addElement (acc:Map<int,int>) element =
if acc.ContainsKey element then acc.Add(element, acc.[element] + 1)
else acc.Add(element, 1)
(Map.empty, numbers)
||> Seq.fold (addElement)
|> Map.iter (printfn "%A - %A")
Print:
1 - 1
2 - 2
3 - 3
4 - 1
5 - 2
Link:
https://dotnetfiddle.net/yFw4Jq

Your example code uses Map, but, assuming Dictionary like you said, such a function could be written:
Seq.countBy id >> dict

Related

how to calculate the max by column in a list of lists, with F#

With the following data (random strings):
let data =
[
["shi"; "cjwocij"; "cjwijo"]
["abs"; "djw"; "djwjdwojdow"]
["djido"; "dkwpkw"; "dpfkpeoep"]
]
I would like to calculate the max length by column.
I can transform the data into a list of lists of lengths:
data |> List.map (fun r -> r |> List.map (fun x -> x.Length))
index value
0 [ 3; 7; 6 ]
1 [ 3; 3; 11 ]
2 [ 5; 6; 9 ]
but ultimately I'd like to reduce it to:
[5; 7; 11]
by taking the max of each column
I thought I could do a fold and take the first row as a starting point, but it looks like it'll be quite convoluted.
For context: it's for a function that will take a grid and display it with proper spacing / formatting; all rows must have the same number of elements.
You need List.transpose. This turns rows into columns and vice versa.
data
|> List.map (fun r -> r |> List.map (fun x -> x.Length))
|> List.transpose
|> List.map List.max
val data : string list list =
[["shi"; "cjwocij"; "cjwijo"]; ["abs"; "djw"; "djwjdwojdow"];
["djido"; "dkwpkw"; "dpfkpeoep"]]
val it : int list = [5; 7; 11]
Here is a quick explicit version of transpose that might help (or hinder?) you grokking this:
let transpose lists =
[0 .. (List.length (List.head lists)) - 1]
|> List.map (fun col -> List.map (fun row -> List.item col row) lists )
This is the recursive version for completeness but I think the above is clearer if you are new to F#.
let rec transpose = function
| (_::_)::_ as l -> List.map List.head l :: transpose (List.map List.tail l)
| _ -> []
Update: I answered this in a comment but for others wondering over the second recursive solution:
The (_::_) ensures that a list is not empty. This is the same as (h::t) but we don't need to use h and t and so put the don't care place holder _ instead.
The second :: makes sure that the list of lists (listoflists) is non-empty or that (h::t)::c = (head of listoflists)::tail of listoflists so h::t is the first row, and c is all the other rows.
(_::_)::_ <=> (headRow0::tailRow0)::tailRows

How to copy elements in a list different number of times?

If I have a list consisting of elements [5;10;15], how can I get an output array in which the number of times element x from the input list is repeated x/5 times, or using any other integral expression to specify the number of repetitions?
So like for this list, the expected output should be [5; 10; 10; 15; 15; 15]
First, transform every element of the input list into a list with that many elements. To transform every element of a list, use List.map. To create a list with a given number of elements, use List.replicate:
let f lst =
lst
|> List.map (fun x -> List.replicate (x/5) x)
Let's test that:
> f [5; 10]
[ [5]; [10; 10] ]
And then, all that's left to do is concatenate all those lists into a big list using List.concat:
let f lst =
lst
|> List.map (fun x -> List.replicate (x/5) x)
|> List.concat
Or you can fuse map and concat together in collect:
let f lst =
lst
|> List.collect (fun x -> List.replicate (x/5) x)
You can define the following function returning a sequence using a sequence expression with nested for loops:
let repeatedSeq (s, itemCount) =
seq { for item in s do for i in 1..itemCount(item) -> item }
And then do:
let list = [5; 10; 15]
let repeatedList = repeatedSeq(list, fun i -> i/5) |> Seq.toList
Which results in [5; 10; 10; 15; 15; 15] as required. This approach avoids materializing any intermediate sequences as lists or arrays.
If you want your final result to be an array do |> Seq.toArray instead.
Demo fiddle here.

How to convert a 2d array to a list of lists in F#

I have a 2d array of floats:
let scores = Array2D.init<float> width height (fun _ _ -> 0.)
and I would like to convert it to a list of lists where I have a list of rows and each of these row is a list of column values.
for example:
[
1, 2, 3
4, 5, 6
7, 8, 9
]
would become:
[
[1, 2, 3]
[4, 5, 6]
[7, 8, 9]
]
I found this question: F# convert Array2 into a list
but it converts the 2d array into a list, I'm trying to find how to convert it to a list of list.
I could iterate through the elements and build the list, but I'm sure there has to be a better way.
This is made quite readable by F#'s slice operators (now in C# 8 too!).
To slice a multi-dimensional array you can use .[range,range].
For example, .[*,n] for the n-th column, and .[n,*] for the n-th row.
The final piece we need is the height of the array, which is Dimension 0, given by
array.GetLength 0
Now it becomes trivial to slice up the 2D array, using a list comprehension.
[
let height = arr.GetLength 0
for row in 0..height-1 do
yield arr.[row,*] |> List.ofArray
]
For non-zero indexed arrays, as suggested by Henrik Hansen, it is preferable to use:
[
for i in arr.GetLowerBound(0)..arr.GetUpperBound(0)
do yield arr.[i,*] |> List.ofArray
]
Test
let counter = ref 0
//generate the test array
let arr = Array2D.init (3) (3) (fun _ _ -> Interlocked.Increment(counter))
arr |> printfn "%A"
let lists =
[
let height = arr.GetLength 0
for row in 0..height - 1 do
yield arr.[row,*] |> List.ofArray
]
lists |> printfn "%A"
Output:
[[1; 2; 3]
[4; 5; 6]
[7; 8; 9]]
[[1; 2; 3]; [4; 5; 6]; [7; 8; 9]]
Another way building on Asti's ideas:
module Array2D =
let toListOfLists (arr2d: 'a [,]) = [ yield! [arr2d.GetLowerBound(0)..arr2d.GetUpperBound(0)] |> List.map (fun i -> arr2d.[i,*] |> List.ofArray) ]
let base002D = Array2D.init 5 5 (fun x y -> (x, y))
let base152D = Array2D.initBased 1 5 5 5 (fun x y -> (x, y))
printfn "%A" (base002D |> Array2D.toListOfLists)
printfn "%A" (base152D |> Array2D.toListOfLists)
It works with different bases.

How to multiply two two nth elements of a list in F#

So i am trying to multiply the nth element of one list with the nth element of another list and add them together
let listMulti xList yList =
|> [for x in xList do
for y in yList do
yield x*y ] // multiplies all the elements on x with y
|> List.filter(fun x-> List.nth % List.length (xList) =1 ) //gets the elements 1 , 4, 7 for a list of size 3. This is scalable
|> List.sum //add them all up
So the idea here is
>listMulti [1;2;3][4;5;6];;
val it : int = 32
So 1*4 + 2 *5 + 3*6 = 32
,but instead im getting
error FS0010: Unexpected infix operator in binding
Help?
The error is because you are using List.nth in a weird way.
I would do something like
List.zip xlist ylist
|> List.sumBy (fun (a,b) -> a*b)
Here list.zip combines the lists - so if you had [1;2;3] and [4;5;6] you get [(1,4);(2,5);(3,6)]. Then you just multiply and sum in one go.

Idiomatic way of aggregating denormalized data

I have a set of data of arrays of arrays. As an example
[[1,3],
[4,3],
[1,2],
[7,2]]
I'd like to transform this to
[(3,[1,4])
(2,[1,7])]
that is: create an array of tuples, where the first member is from index 1 of the original and the array is all the values of index 0 from the original grouped based on index 1. I can solve this imperatively but would like to do it in a more FP kind of way
Use Seq.groupBy in combination with a few maps will get the desired result
[[1;3];
[4;3];
[1;2];
[7;2]]
|> Seq.groupBy (fun (a::b) -> b)
|> Seq.map (fun (a,b) -> a,b|> Seq.toList)
|> Seq.map (fun (a,b) -> a,b|>List.map (fun (c::d) -> c ))
F# is a statically typed functional programming language so the first thing you want to do is convert your input into a typeful representation such as a list of pairs of ints:
[ 1, 3
4, 3
1, 2
7, 2 ]
Then you can pipe it through the Seq.groupBy function using the snd function to key on the second element of each pair:
|> Seq.groupBy snd
This gives you [3, [1, 3; 4, 3]; ...] etc. so you want to map over the right hand sides extracting just the values (i.e. stripping out the keys) using the fst function:
|> Seq.map (fun (k, kvs) -> k, Seq.map fst kvs)
This gives your desired answer: [(3, [1; 4]); (2, [1; 7])].
Similar to #John's answer, but assume that inner collections are arrays with at least two elements:
[|[|1; 3|];
[|4; 3|];
[|1; 2|];
[|7; 2|]|]
|> Seq.map (fun arr -> arr.[0], arr.[1])
|> Seq.groupBy snd
|> Seq.map (fun (k, v) -> k, Seq.map fst v)
// val it : seq<int * seq<int>> = seq [(3, seq [1; 4]); (2, seq [1; 7])]
My answer is not essentially different to the answers above, but it uses a bit of combinatory logic, so it looks more idiomatic (to me). Also, it has some validity check.
Apply2 is essentially an S combinator.
let data =
[[1;3];
[4;3];
[1;2];
[7;2]]
// Apply2 operator applies two functions to x
// and returns both results as a tuple
let (.&.) f g x = f x, g x
// A naive validator for sequences
let assert' predicate message xs =
if not <| Seq.forall predicate xs then
failwith message
xs
let aggregate data =
data
// validate the input
|> assert' (List.length >> (=) 2) "All elements must be of length of two"
// essentially, convert a 2-element list to a tuple
|> Seq.map (List.head .&. (List.tail >> List.head))
// group over the second element of a tuple
|> Seq.groupBy snd
// we no longer need the key element in a tuple, so remove it
|> Seq.map (fst .&. (snd >> Seq.map fst))
aggregate data |> printf "%A"

Resources