How to List.sum a List (Maybe Float)? - list

I am trying to convert strings to floats and find their sum:
> String.split "," "0.2,0.3,3.1"
> List.map String.toFloat ["0.2","0.3","3.1"]
> List.sum [Just 0.2,Just 0.3,Just 3.1]
But I'm getting these compiler messages:
This argument is a list of type:
List (Maybe Float)
But `sum` needs the 1st argument to be:
List number
Hint: Use Maybe.withDefault to handle possible errors. Longer term, it is
usually better to write out the full `case` though!
How can I get the sum of these values?

You have created a List (Maybe Float), but you need a List Float (number is a special type which can be either Int or Float). This means that you need to handle the case when the value in the list is Nothing. The error message suggests using Maybe.withDefault, which would look something like this:
"0.2,0.3,3.1"
|> String.split ","
|> List.map String.toFloat
|> List.map (Maybe.withDefault 0)
|> List.sum
Alternatively, List.filterMap is designed to take a function which returns a Maybe and remove Nothing values. In this case, String.toFloat is that kind of function, so you could to this instead:
"0.2,0.3,3.1"
|> String.split ","
|> List.filterMap String.toFloat
|> List.sum

As the error message points out, you need to handle the Nothing case. Assuming you simply want to discard those values, you can run your list through List.filterMap.
> l = [Just 0.2,Just 0.3,Just 3.1,Nothing]
[Just 0.2,Just 0.3,Just 3.1]
: List (Maybe Float)
> List.filterMap identity l |> List.sum
3.6 : Float
You can compose a function to reuse your logic:
> justSum = List.filterMap identity >> List.sum
<function> : List (Maybe number) -> number
> justSum l
3.6 : Float

String.toFloat returns Nothing when the string is not a valid float. You need to decide what happens when you have a string like this:
"0.2,0.3,3.1,h"
Because it contains h which is not a number, running String.split "," then List.map String.toFloat will produce this result:
[Just 0.2, Just 0.3, Just 3.1, Nothing]
Other answers suggest that you use List.filterMap to ignore the invalid strings. But if you instead want the sum to be Nothing if any strings are invalid, you can use Maybe.Extra.combine like this:
import Maybe.Extra
"0.2,0.3,3.1"
|> String.split ","
|> List.map String.toFloat
|> Maybe.Extra.combine
|> Maybe.map List.sum

You can use the following function:
sumMaybes : List (Maybe number) -> Maybe number
sumMaybes = List.foldl (Maybe.map2 (+)) (Just 0)
-- examples
sumMaybes [Just 1, Just 2] == Just 3
sumMaybes [Nothing, Just 2] == Nothing
sumMaybes [] = Just 0

Related

counting number of times a key is in map

I have the following code:
type Film = (Fan, Title, Review)
filmRating :: [Film] -> [(Fan, Int)]
filmRating l = undefined
I want to be able to give a list:
[("fan1", "film1", 3), ("fan1", "film2", 3), ("fan3", "film1", 5), ("fan4", "film3", 8)]
Now the function wants me to outout a list with how many films a fan watched. so with the list above, I should get:
[("fan1", 2). ("fan3", 1), ("fan4", 1)]
I need to use map and set so I ended up with this
titlesFan :: (Ord k, Ord a) => [(k, a, c)] -> [(k, [a])]
titlesFan l = Map.fromListWith (++) [(f, [t]) | (f, t, _) <- l]
and I can't seem to be able to get the length as it just gives 1
The length of a pair is always 1*:
> length (False, "abc")
1
Probably this is what's happening to you, accidentally. Instead, ask for the length of the second part of the tuple:
> length . snd $ (False, "abc")
3
* If you think of (Bool, String) as being a container of Strings, it's clear that there's always exactly one String in that container, which justifies this result. Though of course whether or not you consider the thought of (Bool, String) being a container of Strings to be justified is a different thing entirely...

Chained calls in Ocaml

I'm trying to express a set of chained calls in a more imperative fashion. For example, image we have a function that takes a list and an element and it appends the element to the end of the list:
let insert l e =
l # [e]
I want to insert a few elements, one at a time. A functional way to do this could be:
let myList = insert (insert (insert [] 3) 4) 5)
I've recently learned about the |> operator, which helps with expressiveness. Together with currying, it can lead to a clean chaining. The problem is that we need to bind the second argument first. This requires defining a function to reverse the arguments (which is actually what |> does :P):
let myList =
let insertIn l e = insert e l in
[] |>
insertIn 3 |>
insertIn 4 |>
insertIn 5
;;
This is almost what I want, except the need to defined insertIn. Is there a cleaner way to do this?
I was hoping there was a special operator like $ which could represent the return value of the previous function:
let myList =
[] |>
insert $ 3 |>
insert $ 4 |>
insert $ 5
;;
One possible approach, which is common in Haskell, is using flip:
let flip f x y = f y x
let myList =
[] |>
flip insert 3 |>
flip insert 4 |>
flip insert 5
But really, if the insert function is one that you wrote yourself, then you should rather consider changing its definition in either one of these ways:
Flip its arguments so that the list comes last, aka "standard library style":
let insert e l =
l # [e]
let myList =
[] |>
insert 3 |>
insert 4 |>
insert 5
Use a named argument, which allows you to pass it out of order, aka "Core style":
let insert l ~elt:e =
l # [e]
let myList =
[] |>
insert ~elt:3 |>
insert ~elt:4 |>
insert ~elt:5
(Also, a side note: your insert is very inefficient because you're copying the whole l every time; lists are designed to be constructed by prepending elements to the front with ::, not appending to the back.)
let (|>) x f y = f x y;;
let myList =
(((
[] |>
insert ) 3 |>
insert ) 4 |>
insert ) 5
;;
val myList : int list = [3; 4; 5]

Adding no value to return list

I'm having a problem with understanding how F# works. I come from C# and I think that I'm trying to make F# work like C#. My biggest problem is returning values in the correct format.
Example:
Let's say I have function that takes a list of integers and an integer.
Function should print a list of indexes where values from list match passed integer.
My code:
let indeks myList n = myList |> List.mapi (fun i x -> if x=n then i else 0);;
indeks [0..4] 3;;
However it returns:
val it : int list = [0; 0; 0; 3; 0]
instead of just [3] as I cannot ommit else in that statement.
Also I have targeted signature of -> int list -> int -> int list and I get something else.
Same goes for problem no. 2 where I want to provide an integer and print every number from 0 to this integer n times (where n is the iterated value):
example:
MultiplyValues 3;;
output: [1;2;2;3;3;3]
Best I could do was to create list of lists.
What am I missing when returning elements?
How do I add nothing to the return
example: if x=n then n else AddNothingToTheReturn
Use List.choose:
let indeks lst n =
lst
|> List.mapi (fun i s -> if s = n then Some i else None)
|> List.choose id
Sorry, I didn't notice that you had a second problem too. For that you can use List.collect:
let f (n : int) : list<int> =
[1 .. n]
|> List.collect (fun s -> List.init s (fun t -> s))
printfn "%A" (f 3) // [1; 2; 2; 3; 3; 3]
Please read the documentation for List.collect for more information.
EDIT
Following s952163's lead, here is another version of the first solution without the Option type:
let indeks (lst : list<int>) (n : int) : list<int> =
lst
|> List.fold (fun (s, t) u -> s + 1, (if u = n then (s :: t) else t)) (0, [])
|> (snd >> List.rev)
This one traverses the original list once, and the (potentially much shorter) newly formed list once.
The previous answer is quite idiomatic. Here's one solution that avoids the use of Option types and id:
let indeks2 lst n =
lst
|> List.mapi (fun i x -> (i,x))
|> List.filter (fun x -> (fst x) % n = 0 )
|> List.map snd
You can modify the filter function to match your needs.
If you plan to generate lots of sequences it might be a good idea to explore Sequence (list) comprehensions:
[for i in 1..10 do
yield! List.replicate i i]
If statements are an expression in F# and they return a value. In this case both the IF and ELSE branch must return the same type of value. Using Some/None (Option type) gets around this. There are some cases where you can get away with just using If.

F# System.InvalidOperationException: Collection was modified; enumeration operation may not execute

i am encountering this problem in F#
[not C# where there is already a similar post with a similar answer]
I understand its not possible to modify a Dictionary while enumerating it in a for loop
how should i go around that ?
let edgelist1 = [(1,2,3.0f);(1,2,4.0f);(5,6,7.0f);(5,6,8.0f)]
let dict_edges = new Dictionary<int*int,(int*int*float32) list>()
for x in edgelist1 do dict_edges.Add ((fun (a,b,c)-> (a,b)) x, x)
for k in dict_edges.Keys do dict_edges.[k] <- (dict_edges.[k] |> List.rev)
System.InvalidOperationException: Collection was modified; enumeration
operation may not execute.
at System.ThrowHelper.ThrowInvalidOperationException(ExceptionResource
resource) at
System.Collections.Generic.Dictionary`2.KeyCollection.Enumerator.MoveNext()
at .$FSI_0101.main#()
individually this is working
dict_edges.[(1,2)] <- dict_edges.[(1,2)] |> List.rev;;
in the for loop i need just to change dictionary values, not keys.
thanks
You can copy all the keys into a temporary list, and then iterate over that list while modifying the original dictionary:
for k in (dict_edges.Keys |> Seq.toList) do
dict_edges.[k] <- (dict_edges.[k] |> List.rev)
But I would strongly advise you to rethink your approach and get rid of in-place mutation. This little problem you're facing right now is only the first taste of what could go wrong with a mutation-based program.
The code you posted is not even syntactically correct, so it's not clear what precisely you are trying to achieve (compiler screams at ((fun (a,b,c)-> (a,b)) x, x) saying that it expects the second x to be a list)
I guess what you are after is: You have a list of weighted edges, where there can be multiple edges between nodes. You'd like to collapse them into a canonical form, where you have all edges grouped that connect any pair of nodes (i,j). Just use any of the groupBy library functions, and you're good:
let map_edges =
edgelist1
|> List.groupBy (fun (a, b, _) -> (a, b))
|> Map.ofList
In the current code you are using ((fun (a,b,c)-> (a,b)) x, x) to extract members of a tuple. Instead, use patterns right in the for expression:
for (a, b, c) in edgelist1 do dict_edges.Add ((a, b), [(a, b, c)])
(I've added [] to make it at least compile)
Note also that you are duplicating information: You store the node tuple in the keys and in the values of the list, making the data structure possibly inconsistent and larger. Consider the following:
let map_edges =
edgelist1
|> List.map (fun (a, b, c) -> (a, b), c)
|> List.groupBy fst
|> List.map (fun (nodeTuple, edgeList) ->
nodeTuple, (edgeList |> List.map snd))
|> Map.ofList
map_edges
|> Map.iter (fun (nodeI, nodeJ) edgeList ->
edgeList
|> Seq.map string
|> String.concat "; "
|> printfn "Nodes (%i, %i): weights %s" nodeI nodeJ
)
(You may want to use sequences as the intermediate representation rather than list)
Wouldn't it be easier to just say dict_edges = dict_edges.map( $0.reverse())
Sorry about the bad f# syntax

Sorting list of tuples f#

this should be really quick, I have a list of tuples like [("8585", 1);("9232",1);etc] where the second item corresponds to the number of ocurrences the item in "" makes. I was wondering how could i arrange my list from the one that makes more ocurrences to the one that makes least.
f#!
Use sortBy:
let lst = [("8585", 1);("9232",3)]
List.sortBy (fun (_, y) -> -y) lst
Like Gustavo implied, if it's numeric, you can negate it to reverse its order in sorting. That's what the unary operator ~- is for.
Your peculiar choice of data, that is tuples of 'something * int, let me suspect that you are counting the number of certain occurences, and for that Seq.countBy may help (sorry, no list equivalent).
// Your key, Some data
[ "9232", false
"8585", false
"9232", true
"9232", true ]
|> Seq.countBy fst
|> Seq.sortBy (snd >> (~-))
// val it : seq<string * int> = seq [("9232", 3); ("8585", 1)]
That's sorted by the count (snd element of the tuple) of the key (fst element of the tuple) negated.
F# does have List.sortByDescending, so you could have:
[("8585", 1);("9232",3)]
|> List.sortByDescending (fun (_,y) -> y)