I want to find tuple in a set by first two values and return third value of the tuple (or None if found nothing). I woluld like something like that:
type Point = (int * int * int)
type Path = Set<Point>
let f (x:int) (y:int) (p:Path) : int Option =
if Set.exists ((=) (x, y, _z)) p
then Some _z
else None
let p:Path = Set.ofList [ (0, 1, 100); (1, 1, 500); (1, 2, 50); ]
f 1 2 p
But this not works because, apparently, pattern matching does not allowed in expressions. What is the right approach? Thanks.
You can convert the set to list and use List.tryFind
let f (x:int) (y:int) (p:Path) : int Option =
Set.toList p
|> List.tryFind (fun (px, py, _) -> x = px && y = py)
|> Option.map (fun (_, _, pz) -> pz)
Iterating on hvester's answer:
let f (x:int) (y:int) (p:Path) : int Option =
p |> Seq.tryPick (function
| x', y', z' when x = x' && y = y' -> Some z'
| _ -> None)
tryPick essentially does a find and map in one step.
This is a pretty neat solution with fold
let f x y p = Set.fold (function |None -> (fun (x_,y_,z) -> if x=x_ && y=y_ then Some z else None) |f ->fun _ -> f) None p
Is this what you want to do?
let f (x:int) (y:int) (p:Path) : int Option =
match p |> Set.filter (fun (x', y', _) -> x' = x && y' = y) |> Set.toList with
| [(_, _, z)] -> Some z
| [] -> None
| _ -> failwith "More than one point was found!"
Example:
> let p:Path = Set.ofList [ (0, 1, 100); (1, 1, 500); (1, 2, 50); ];;
val p : Path = set [(0, 1, 100); (1, 1, 500); (1, 2, 50)]
> f 1 2 p;;
val it : Option<int> = Some 50
Related
Let's say I have a list in F# like this: [5,-2, -6, 7, -2, 2, 14, 2]
I want to write a function that will use List.fold to return a new list such as [5, -8, 7, -2, 18]
My template looks like this:
let sumAdjacentOfSameSign (lst :int list) : int list =
let f x y =
if x.Length = 0 then
[y]
elif System.Math.Sign(x) = System.Math.Sign(y) then ...
else y :: x
List.fold f [] lst
I need to fill in the ... part but can't quite say how.
Making the fewest changes to your code, I would do this:
let sumAdjacentOfSameSign (lst :int list) : int list =
let f (x : int list) (y : int) =
if x.Length = 0 then
[y]
elif System.Math.Sign(x.Head) = System.Math.Sign(y) then
(x.Head + y) :: x.Tail
else y :: x
List.fold f [] lst
|> List.rev // note that you have to reverse the resulting list
But I would suggest simplifying f to:
let f (x : int list) (y : int) =
match x with
| head :: tail when
System.Math.Sign(head) = System.Math.Sign(y) ->
(head + y) :: tail
| _ -> y :: x
Suppose I have a collection like [ "a"; "b"; "c" ] and I want to test every element against every other element.
I could generate all pairs like this:
let combinations xs =
Seq.allPairs xs xs
|> Seq.filter (fun (x, y) -> x <> y)
|> Seq.toList
combinations [ "a"; "b"; "c" ]
// [("a", "b"); ("a", "c"); ("b", "a"); ("b", "c"); ("c", "a"); ("c", "b")]
But for my test, I always know that f x y = f y x (since f is symmetric), so I want to trim the number of combinations tested:
let combinations xs =
Seq.allPairs xs xs
|> Seq.filter (fun (x, y) -> x <> y && x < y)
|> Seq.toList
combinations [ "a"; "b"; "c" ]
// [("a", "b"); ("a", "c"); ("b", "c")]
But this:
Doesn't seem like an efficient way to generate the test cases
Requires that x : comparison, which I don't think should be necessary
How should I implement this in F#?
Don't know about efficient - this looks like you need to cache the pairs already generated and filter on their presence in the cache.
The library implementation of Seq.allPairs goes along these lines:
let allPairs source1 source2 =
source1 |> Seq.collect (fun x -> source2 |> Seq.map (fun y -> x, y))
// val allPairs : source1:seq<'a> -> source2:seq<'b> -> seq<'a * 'b>
Then you integrate the caching and filtering into this, constraining both sequences to type seq<'a> and introducing the equality constraint.
let allPairs1 source1 source2 =
let h = System.Collections.Generic.HashSet()
source1 |> Seq.collect (fun x ->
source2 |> Seq.choose (fun y ->
if x = y || h.Contains (x, y) || h.Contains (y, x) then None
else h.Add (x, y) |> ignore; Some (x, y) ) )
// val allPairs1 :
// source1:seq<'a> -> source2:seq<'a> -> seq<'a * 'a> when 'a : equality
Test
allPairs1 [1..3] [2..4] |> Seq.toList
// val it : (int * int) list = [(1, 2); (1, 3); (1, 4); (2, 3); (2, 4); (3, 4)]
Because f is commutative, the simplest way to get all combinations is to project each item into a pair with the remainder of the list.
let rec combinations = function
| [] -> []
| x::xs -> (xs |> List.map (fun y -> (x, y))) # (combinations xs)
We don't need any comparison constraint.
let xs = [1; 2; 3; 4;]
combinations xs // [(1, 2); (1, 3); (1, 4); (2, 3); (2, 4); (3, 4)]
Checking the results with #kaefer's method:
combinations xs = (allPairs1 xs xs |> Seq.toList) // true
Another solution that assumes all elements are distinct (it uses position as identity):
let allSymmetricPairs xs =
seq {
let xs = Seq.toArray xs
for i = 0 to Array.length xs - 2 do
for j = i + 1 to Array.length xs - 1 do
yield xs.[i], xs.[j]
}
We can also pre-allocate the array, which may be faster if you plan to pull the whole sequence:
let allSymmetricPairs xs =
let xs = Seq.toArray xs
let n = Array.length xs
let result = Array.zeroCreate (n * (n - 1) / 2)
let mutable k = 0
for i = 0 to n - 2 do
for j = i + 1 to n - 1 do
result.[k] <- xs.[i], xs.[j]
k <- k + 1
result
Please help.
Develop a function that takes a list of integers that defines it the longest continuous chain of identical numbers. The result of the function must be a pair (number, length of the chain)
my code:-
let findMaxSeq (nums: int list) =
let foldFun (curN, len, (curWinN, curWinLen)) n =
match len, curWinLen with
| 0, 0 -> (n, 1, (n,1))
| 0, _ -> (n, 1, (curWinN,curWinLen))
| _ when n = curN ->
let newLen = len+1
if (newLen>curWinLen) then (n, newLen, (n, newLen)) else (n, newLen, (curWinN, curWinLen))
| _ -> (n, 1, (curWinN, curWinLen))
let (_, _, (winner)) = nums |> List.fold foldFun (0, 0, (0, 0))
winner
but don't compile - in second let i have error:-
Block following this 'let' is unfinished. Expect an expression.
Could indentation be the problem? It compiles when formatted like this:
let findMaxSeq (nums: int list) =
let foldFun (curN, len, (curWinN, curWinLen)) n =
match len, curWinLen with
| 0, 0 -> (n, 1, (n,1))
| 0, _ -> (n, 1, (curWinN,curWinLen))
| _ when n = curN ->
let newLen = len+1
if (newLen>curWinLen) then (n, newLen, (n, newLen))
else (n, newLen, (curWinN, curWinLen))
| _ -> (n, 1, (curWinN, curWinLen))
let (_, _, (winner)) = nums |> List.fold foldFun (0, 0, (0, 0))
winner
This looked like a fun challenge, so I took a stab at it.
let findMaxRepeatedValue xs =
let rec loop (maxVal, maxCount) (curVal, curCount) = function
| [] -> if curCount > maxCount then (curVal, curCount) else (maxVal, maxCount)
| x::xs when x = curVal -> loop (maxVal, maxCount) (curVal, curCount + 1) xs
| x::xs ->
if curCount > maxCount then loop (curVal, curCount) (x, 1) xs
else loop (maxVal, maxCount) (x, 1) xs
match xs with
| [] -> invalidArg "xs" "empty list"
| [x] -> (x, 1)
| x::xs -> loop (x, 1) (x, 1) xs
Since your main question has been answered, here's yet another option/approach, for fun and profit :)
let longestChain nums =
let rec chain lst (num, cnt) = seq {
match lst with
| x :: xs -> if x = num then
yield! chain xs (num, cnt+1)
else
yield (num, cnt)
yield! chain xs (x, 1)
| [] -> yield (num, cnt)
}
match nums with
| x :: xs -> chain xs (x, 1) |> Seq.maxBy snd
| [] -> failwith "Cannot find the longest chain in an empty list"
As Daniel pointed out, this was just an indentation problem - F# is an indentation sensitive language (spaces have meaning) and so you need to indent nested blocks further. Your function works just fine when it is indented correctly!
let findMaxSeq (nums: int list) =
let foldFun (curN, len, (curWinN, curWinLen)) n =
match len, curWinLen with
| 0, 0 -> (n, 1, (n,1))
| 0, _ -> (n, 1, (curWinN,curWinLen))
| _ when n = curN ->
let newLen = len+1
if (newLen>curWinLen) then
(n, newLen, (n, newLen))
else
(n, newLen, (curWinN, curWinLen))
| _ -> (n, 1, (curWinN, curWinLen))
let (_, _, (winner)) = nums |> List.fold foldFun (0, 0, (0, 0))
winner
findMaxSeq [1;2;2;2;3;3;1;1;1;1;1;4;4]
Note that:
the body of function foldFun is indented further than the let that defines the function.
the body of the complex pattern (matching when n=curN) is also indented further
I also split if then to multiple lines (for readability - this is not required)
Daniel's solution is perfectly fine too - but since you asked about a version based on List.fold, I thought I'd answer with a corrected version of your original code.
As an aside, if you wanted to do more operations like this on some actual data (like time series) rather than just solve this for the purpose of learning F#, then Deedle which is a library for working with series data has a nice abstraction called chunkWhile that splits series into chunks while some condition holds (e.g. while the values are the same) and makes it pretty easy to write this:
#r "lib/Deedle.dll"
open Deedle
let findMaxSeq values =
let s = Series.ofValues values
s |> Series.chunkWhile (fun k1 k2 -> s.[k1] = s.[k2])
|> Series.map(fun k chunk -> s.[k], Series.countKeys chunk)
|> Series.values
|> Seq.maxBy snd
findMaxSeq [1;2;2;2;3;3;1;1;1;1;1;4;4]
Here's an attempt which is generic and uses standard library functions. Since you didn't say what the answer should be when the input sequence is empty, I'm not returning a pair of number * length directly, but wrap that up in an option.
let inline findMaxSeq xs =
xs
|> Seq.scan (fun state x ->
match state with
| Some (y, i) when x = y -> Some (x, i + 1)
| _ -> Some (x, 1) )
None
|> Seq.maxBy (function
| Some (_, i) -> i
| _ -> 0 )
findMaxSeq [1;2;2;2;3;3;1;1;1;1;1;4;4] // Some (1, 5)
findMaxSeq Seq.empty<int> // None
Sorry, but most F# code I've seen her so far looks to me like C# in disguise. I am sure functional F# programmers can do better, along the lines of this Haskell solution:
maxrv = maximumBy (comparing fst) . map (\xs -> (length xs, xs)) . group
I'm new to F# and I'm curious if this can still be optimized further. I am not particularly sure if I've done this correctly as well. I'm curious particularly on the last line as it looks really long and hideous.
I've searched over google, but only Roman Numeral to Number solutions only show up, so I'm having a hard time comparing.
type RomanDigit = I | IV | V | IX
let rec romanNumeral number =
let values = [ 9; 5; 4; 1 ]
let capture number values =
values
|> Seq.find ( fun x -> number >= x )
let toRomanDigit x =
match x with
| 9 -> IX
| 5 -> V
| 4 -> IV
| 1 -> I
match number with
| 0 -> []
| int -> Seq.toList ( Seq.concat [ [ toRomanDigit ( capture number values ) ]; romanNumeral ( number - ( capture number values ) ) ] )
Thanks for anyone who can help with this problem.
A slightly shorter way of recursively finding the largest digit representation that can be subtracted from the value (using List.find):
let units =
[1000, "M"
900, "CM"
500, "D"
400, "CD"
100, "C"
90, "XC"
50, "L"
40, "XL"
10, "X"
9, "IX"
5, "V"
4, "IV"
1, "I"]
let rec toRomanNumeral = function
| 0 -> ""
| n ->
let x, s = units |> List.find (fun (x,s) -> x <= n)
s + toRomanNumeral (n-x)
If I had to use a Discriminated Union to represent the roman letters I would not include IV and IX.
type RomanDigit = I|V|X
let numberToRoman n =
let (r, diff) =
if n > 8 then [X], n - 10
elif n > 3 then [V], n - 5
else [], n
if diff < 0 then I::r
else r # (List.replicate diff I)
Then, based in this solution you can go further and extend it to all numbers.
Here's my first attempt, using fold and partial application:
type RomanDigit = I|V|X|L|C|D|M
let numberToRoman n i v x =
let (r, diff) =
if n > 8 then [x], n - 10
elif n > 3 then [v], n - 5
else [], n
if diff < 0 then i::r
else r # (List.replicate diff i)
let allDigits (n:int) =
let (_, f) =
[(I,V); (X,L); (C,D)]
|> List.fold (fun (n, f) (i, v) ->
(n / 10, fun x -> (numberToRoman (n % 10) i v x) # f i)) (n, (fun _ -> []))
f M
Here's a tail-recursive version of #Philip Trelford's answer:
let toRomanNumeral n =
let rec iter acc n =
match n with
| 0 -> acc
| n ->
let x, s = units |> List.find (fun (x, _) -> x <= n)
iter (acc + s) (n-x)
iter "" n
I'm trying to make a custom fold which goes through my sequence, and takes 2 Teams a time and assign them to a Match and then return a Match list in the end.
My current code is:
let myFold f s =
let rec myFold' f s acc =
match s with
| (a1::a2::a) -> f a1 a2::acc
| _ -> acc
myFold' f s []
Which gives me (int -> int) list
But obviously thats not going to work... What am I doing wrong?
-> I know that I just can create a recrusive function special made for this scenario, however I want to make it so abstract as possible for reuse.
Im' not quite sure that I get what you want to achieve. From sequence [1;2;3;4] you want to get [(1,2); (3,4)] or [(1,2); (2,3); (3,4)] ?
let fold f s =
let rec impl acc = function
| x::y::rest -> impl ((f x y)::acc) rest
| _ -> List.rev acc
impl [] s
let s = [1;2;3;4;5;6]
let r = fold (fun x y -> x,y) s // [(1, 2); (3, 4); (5, 6)]
let fold2 f s = Seq.pairwise s |> Seq.map f |> Seq.toList
let r2 = fold2 id s // [(1, 2); (2, 3); (3, 4); (4, 5); (5, 6)]