Get the count of distinct values from a Sequence in F# - f#

I have a sequence of Country names in F#. I want to get how many of each distinct country entries do I have in the sequence.
The countBy examples in Microsoft docs and MSDN use if and else to get the Keys, but since I have ~240 distinct entries, I guess that I don't need to make an elif sentence for each entry, right?
So, is there an option to use another sequence to get the keys for the countBy?
#load "packages/FsLab/FsLab.fsx"
open FSharp.Data
open System
type City = JsonProvider<"city.list.json",SampleIsList=true>
let cities = City.GetSamples()
let Countries = seq { for city in cities do yield city.Country.ToString() } |> Seq.sort
let DistinctCountries = Countries |> Seq.distinct
//Something like this
let Count = Seq.countBy DistinctCountries Countries
Anyone interested in my city.list.json
Update
My input sequence is something like this (with a lot more of entries) with each code repeated as many cities for that country are in the original list:
{ "AR","AR","AR","MX","MX" }
As a result I expect:
{("AR", 3),("MX", 2),...}

Countries |> Seq.countBy id
id is the identity function fun x -> x. Use this because the "key" here is the sequence item itself.

You can group the countries and then count the number of entries in each group:
let countsByCountry =
Countries
|> Seq.groupBy id
|> Seq.map (fun (c, cs) -> c, Seq.length cs)
This combination is also implemented as a single function, countBy:
let countsByCountry = Countries |> Seq.countBy id

So, is there an option to use another sequence to get the keys for the countBy?
You do not need to get the keys from somewhere, the function passed to Seq.countBy generates the keys. You should be able to get away with this:
let count =
cities
|> Seq.countBy (fun c -> c.Country.ToString())

Related

Sorting indexes in list of lists - F#

Currently I have a function to return the first elements of each list (floats), within a list to a separate list.
let firstElements list =
match list with
| head::_ -> head
| [] -> 0.00
My question is, how do I expand this to return elements at the same index into different lists while I don't know how long this list is? For example
let biglist = [[1;2;3];[4;5;6];[7;8;9]]
If I did not know the length of this list, what is the most efficient and safest way to get
[[1;4;7];[2;5;8];[3;6;9]]
List.transpose has been added recently to FSharp.Core
let biglist = [[1;2;3];[4;5;6];[7;8;9]]
let res = biglist |> List.transpose
//val res : int list list = [[1; 4; 7]; [2; 5; 8]; [3; 6; 9]]
You can use the recent added List.transpose function. But it is always good to be good enough to create such functions yourself. If you want to solve the problem yourself, think of a general algorithm to solve your problem. One would be.
From the first element of each list you create a new list
You drop the first element of each list
If you end with empty lists you end, otherwise repeat at step 1)
This could be the first attempt to solve the Problem. Function names are made up, at this point.
let transpose lst =
if allEmpty lst
then // Some Default value, we don't know yet
else ...
The else branch looks like following. First we want to pick the first element of every element. We imagine a function pickFirsts that do this task. So we could write pickFirsts lst. The result is a list that itself is the first element of a new list.
The new list is the result of the remaining list. First we imagine again a function that drops the first element of every sub-list dropFirsts lst. On that list we need to repeat step 1). We do that by a recursive call to transpose.
Overall we get:
let rec transpose lst =
if allEmpty lst
then // Some Default value, we don't know yet
else (pickFirsts lst) :: (transpose (dropFirsts lst))
At this point we can think of the default value. transpose needs to return a value in the case it ends up with an empty list of empty lists. As we use the result of transpose to add an element to it. The results of it must be a list. And the best default value is an empty list. So we end up with.
let rec transpose lst =
if allEmpty lst
then []
else (pickFirsts lst) :: (transpose (dropFirsts lst))
Next we need to implement the remaining functions allEmpty, pickFirsts and dropFirsts.
pickFirst is easy. We need to iterate over each element, and must return the first value. We get the first value of a list by List.head, and iterating over it and turning every element into a new list is what List.map does.
let pickFirsts lst = List.map List.head lst
dropFirsts need to iterate ver each element, and just remove the first element, or in other words keeps the remaining/tail of a list.
let dropFirsts lst = List.map List.tail lst
The remaining allEmpty is a predicate that either return true/false if we have an empty list of lists or not. With a return value of bool, we need another function that allows to return another type is a list. This is usually the reason to use List.fold. An implementation could look like this:
let allEmpty lst =
let folder acc x =
match x with
| [] -> acc
| _ -> false
List.fold folder true lst
It starts with true as the default value. As long it finds empty lists it returns the default value unchanged. As soon there is one element found, in any list, it will return false (Not Empty) as the new default value.
The whole code:
let allEmpty lst =
let folder acc x =
match x with
| [] -> acc
| _ -> false
List.fold folder true lst
let pickFirsts lst = List.map List.head lst
let dropFirsts lst = List.map List.tail lst
let rec transpose lst =
if allEmpty lst
then []
else (pickFirsts lst) :: (transpose (dropFirsts lst))
transpose [[1;2;3];[4;5;6];[7;8;9]]
Another approach would be to turn it into a 2 dimensional mutable array. Also do length checkings. Do the transformation and return the mutable array again as an immutable list.

F# Change element in list and return full new list

I have a list of type (string * (int * int)) list. I want to be able to search through the list, finding the right element by it's string identifier, do a calculation on one of the ints, and then return the full, modified list.
Example:
Given a list
let st = [("a1",(100,10)); ("a2",(50,20)); ("a3",(25,40))]
I'm trying to make a function which gets one of the elements and subtracts number from one of the ints in the tuple.
get ("a2",10) st
//Expected result: st' = [("a1",(100,10)); ("a2",(40,20)); ("a3",(25,40))]
I feel I'm almost there, but am a little stuck with the following function:
let rec get (a,k) st =
match st with
| (a',(n',p'))::rest when a'=a && k<=n' -> (n'-k,p')::rest
| (a',(n',p'))::rest -> (n',p')::get (a,k) rest
| _ -> failwith "Illegal input"
This returns [("a2",(40,20)); ("a3",(25,40))] and is thus missing the first a1 element. Any hints?
Lists are immutable, so if you want to "change one element" you are really creating a new list with one element transformed. The easiest way to do a transformation like this is to use List.map function. I would write something like:
let updateElement key f st =
st |> List.map (fun (k, v) -> if k = key then k, f v else k, v)
updateElement is a helper that takes a key, update function and an input. It returns list where the element with the given key has been transformed using the given function. For example, to increment the first number associated with a2, you can write:
let st = [("a1",(100,10)); ("a2",(50,20)); ("a3",(25,40))]
st |> updateElement "a2" (fun (a, b) -> a + 10, b)
I was looking for a function which would update an element in a list based on the element's data. I couldn't find one in F#5, so wrote one using Tomas' solution:
let updateAt (elemFindFunc: 'a -> bool) (newElem: 'a) (source: 'a list) : 'a list =
source
|> List.map
(fun elem ->
let foundElem = elemFindFunc elem
if foundElem then newElem else elem)
elemFindFunc is the function which consumes an element and returns true if this is the element we want to replace. If this function returns true for multiple elements, then those will be replaced by newElem. Also, if elemFindFunc evaluates to false for all elements, the list will be unaltered.
newElem is the new value you want to replace with. newElem could be replaced by a function like valueFunc: 'a -> 'a if you want to process the element before inserting it.

HOWTO Fix Exception Hell in List.head if list is empty

I need to pass head of a list to List.fold. What is the functional solution to handle ArgumentException for the below case if departments is empty.
let result = employees
|> List.fold (...) (List.head departments)
Here, departments is a list. I did not specify the fold function here for sake of clarity.
Writing a match pattern will make my code awkard.
You'll need to examine the departments list and provide a default if it's empty. You could provide a helper function for that:
let headOrDefault def d =
match d with
| [] -> def
| _ -> List.head d
which you could use like this:
let result =
employees
|> List.fold (...) (headOrDefault defDep departments)
If departments can't be empty, you can use NonEmptyList<'T> provided by Fsharpx.Collections.
let result = employees
|> List.fold (...) (NonEmptyList.head departments)
You don't need to handle ArgumentException because NonEmptyList.head never fails.

Project new values from existing value

I'm writing my very first F# program, the aim being simply to learn F#.
What I want to is provide a list of dates, and attributes (e.g.DayOfWeek, DayOfMonth) of those dates. I have managed to provide the list of dates and I know that the .net Framework gives me everything I need to extract all the attributes, I just can't figure out how to add the attribute as new columns in my list.
Here's what I have so far:
type Span = Span of TimeSpan with
static member (+) (d:DateTime, Span wrapper) = d + wrapper //this is defining the + operator
static member Zero = Span(new TimeSpan(0L))
type Dates() =
let a = DateTime.Parse("01/12/2013")
let b =DateTime.Parse("02/12/2013")
let ts = TimeSpan.FromDays(1.0)
member this.Get() = [a .. Span(ts) .. b]
let mydates = new Dates()
mydates.Get()
When I run that code I get a list of DateTime values, with 2 records in the list. I can now do something like this:
mydates.Get() |> List.map (fun x -> x.DayOfWeek);;
which returns:
val it : DayOfWeek list = [Sunday; Monday]
or
mydates.Get() |> List.map (fun x -> x.DayOfYear);;
which returns:
val it : int list = [335; 336]
That's all great, however what I would like to do is project a list that has 2 "columns" (if columns is the right word) so that my output is (something like):
val it : int list = [(Sunday,335); (Monday,336)]
I hope that explains what I'm after.
thanks
Jamie
For your example, the solution is simple, make the map return a tuple like so
mydates.Get() |> List.map (fun x -> x.DayOfWeek,x.DayOfYear);;

Merge multiple lists of data together by common ID in F#

I have multiple lists of data from 4 different sources with a common set of IDs that I would like to merge together, based on ID, basically ending up with a new list, one for each ID and a single entry for each source.
The objects in the output list from each of the 4 sources look something like this:
type data = {ID : int; value : decimal;}
so, for example I would have:
let sourceA = [data1, data2, data3];
let sourceB = [data1, data2, data3];
let sourceC = [data1, data2, data3];
let sourceD = [data1, data2, data3];
(I realize this code is not valid, just trying to give a basic idea... the lists are actually pulled and generated from a database)
I would then like to take sourceA, sourceB, sourceC and sourceD and process them into a list containing objects something like this:
type dataByID = {ID : int; valueA : decimal; valueB : decimal; valueC : decimal; valueD : decimal; }
...so that I can then print them out in a CSV, with the first column being the ID and coulmns 2 - 5 being data from sources A - D corresponding to the ID in that row.
I'm totally new to F#, so what would be the best way to process this data so that I match up all the source data values by ID??
It seems that you could simply concatenate all the lists and then use Seq.groupBy to get a list that contains unique IDs in the input lists and all values associated with the ID. This can be done using something like:
let data =
[ data1; data2; data3; data4 ] // Create list of lists of items
|> Seq.concat // Concatenate to get a single list of items
|> Seq.groupBy (fun d -> d.ID) // Group elements by ID
seq { for id, values in data ->
// ID is the id and values is a sequence with all values
// (that come from any data source) }
If you want to associate the source (whether it was data1, data2, etc...) with the value then you can first usemap` operation to add an index of the data source:
let addIndex i data =
data |> Seq.map (fun v -> i, v)
let data =
[ List.map (addIndex 1) data1;
List.map (addIndex 2) data2;
List.map (addIndex 3) data3;
List.map (addIndex 4) data4 ]
|> Seq.concat
|> Seq.groupBy (fun (index, d) -> d.ID)
Now, data also contains index of the data source (from 1 to 3), so when iterating over the values, you can use index to find out from which data source the item comes from. Even nicer version can be written using Seq.mapi to iterate over list of data sources and add index to all the values automatically:
let data =
[ data1; data2; data3; data4 ]
|> Seq.mapi (fun index data -> Seq.map (addIndex index) data)
|> Seq.concat
|> Seq.groupBy (fun (index, d) -> d.ID)

Resources