This question already has answers here:
Merge two lists
(6 answers)
Closed 6 years ago.
I am looking to write a recursive function to merge to integer lists in F#
I started with this, but not sure what to do next.
let rec merge xs ys =
match xs with
| [] -> ys
|
let li = [1;3;5;7;]
let ll = [2;4;5;8;]
As I said in my comment, it's probably easiest if you pattern match on xs and ys simultaneously:
let rec merge xs ys =
match xs,ys with
| [],l | l,[] -> l
| x::xs', y::ys' ->
if x < y then x :: (merge xs' ys) //'
else y :: (merge xs ys') //'
I found a way that might suit what the asker wanted. I for one had to solve this very same problem and was barely given a week's worth of lessons on F# so the whole syntax wasn't discussed in class and when I saw the answer above the use of multiple matching ( match lst1, list2 with ... ) I recognized it's use instantly but the professor wouldn't allow it's use, therefor I had to come up with this other alternative. Even thought it's basically the same algorithm it uses more basic code. Just thought I should post it =)
let rec merge2 list1 list2 =
let head list = match list with | [] -> 0 | h::t -> h
let tail list = match list with | [] -> [] | h::t -> t
match list1 with
| [] -> []
| h::t ->
//list2's head is 0 then list is empty then return whats in the first list
//(i.e no more values of second list to compare)
if head list2 = 0 then list1
elif h < head list2 then h :: merge2 t list2
else head list2 :: merge2 list1 (tail list2)
You already have one of the base cases right: If xs is empty, just return ys.
Likewise, if ys empty, return xs.
For the case where both xs and ys are not empty, you need to look at xs's and ys's first elements (let's call them x and y):
If x is less than y, than it needs to be inserted before y in the final list. So you take y and prepend to the result of merging the tail of xs with ys (including y).
Otherwise y needs to come first. So prepend y to the result of merging xs (including x) with the tail of ys.
It's not recursive, but if the inputs aren't sorted:
let merge xs ys = (Seq.append xs ys) |> Seq.sort |> Seq.toList
I would use List.fold to do this:
let merge a b =
List.fold (fun acc x ->
if List.exists ((=)x) acc = false then
elem :: acc
else
acc
) (List.sort a) b
This may not be the fastest way to do it, though.
I don't think this is a recursion problem
let a = [1;3;5]
let b = [2;4;6]
let c = Seq.append a b |> Seq.sort
output from fsi session:
c:
val it : seq<int> = seq [1; 2; 3; 4; ...]
Related
I'm quite a newbie at F# and want to find how many times a value x has occurred in a list ys
So for example multiplicity (2, [1;2;3;4;2]) returns 2. The code I've written below returns 4 on the above example. What am I missing?
let rec multiplicity (x, ys) =
match ys with
| [] -> 0
| y::tail when x=y -> x + multiplicity(x, tail)
| y::tail -> multiplicity(x, tail)
If you're not writing this as a recursive function as a learning exercise, it's probably more idiomatic to use the built-in collection functions:
[1;2;3;4;2] |> Seq.filter ((=) 2) |> Seq.length
[1;2;3;4;2] |> List.sumBy (fun x -> if x = 2 then 1 else 0)
Alright, this is a good example of why it's always a good idea to write down a problem/question.
I figured out, I should do this instead:
let rec multiplicity (x, ys) =
match ys with
| [] -> 0
| y::tail when x=y -> 1 + multiplicity(x, tail)
| y::tail -> multiplicity(x, tail)
It should be 1 and not x, which is added to the recursive call, doh.
I find it's a good idea to replace recursion with fold, so here is another version:
let xs = [1;2;3;4;2]
(0,xs) ||> List.fold (fun acc elem -> match elem with
| 2 -> acc + 1
| _ -> acc)
You can also use countBy, which will return a list of tuples with true and false.
xs |> List.countBy (fun x -> x = 2)
This is how I implemented merge-sort in F# using imperative style:
let merge (l1: List<string>, l2: List<string>) =
let r: List<string> = new List<string>()
let mutable (i,j, cnt1, cnt2) = (0,0, l1.Count, l2.Count)
while i < cnt1 && j < cnt2 do
if l1.[i] <= l2.[j] then
r.Add (l1.[i])
i <- i + 1
else
r.Add (l2.[j])
j <- j + 1
if i = cnt1 then
while j < cnt2 do
r.Add (l2.[j])
j <- j + 1
else
while i < cnt1 do
r.Add (l1.[i])
i <- i + 1
r
Can you convert this to alternate 'functional' styled implementation and explain how it works, if possible? Even though I am studying list comprehensions and all that at the moment, I can't come up with an idea to use it here.
You're using .NET List<'T> which is renamed to ResizeArray<'T> in F# to avoid confusion. If you use functional list, merge function would look like this:
let merge(xs, ys) =
let rec loop xs ys acc =
match xs, ys with
| [], [] -> List.rev acc (* 1 *)
| [], y::ys' -> loop xs ys' (y::acc) (* 2 *)
| x::xs', [] -> loop xs' ys (x::acc) (* 3 *)
| x::xs', y::_ when x <= y -> loop xs' ys (x::acc) (* 4 *)
| _::_, y::ys' -> loop xs ys' (y::acc) (* 5 *)
loop xs ys []
To explain this function in terms of your imperative version:
The 4th and 5th patterns are corresponding to the first while loop where you compare two current elements and add the smaller one into a resulting list.
The 2nd and 3rd patterns are similar to your 2nd and 3rd while loops.
The first pattern is the case where i = cnt1 and j = cnt2 and we should return results. Since a new element is always prepended to the accumulator, we need to reverse it to get a list in the increasing order.
To be precise, your merge function is just one part of merge-sort algorithm. You need a function to split a list in two halves, call merge-sort on two halves and merge two sorted halves into one. The split function below is left for you as an exercise.
let rec mergeSort ls =
match ls with
| [] | [_] -> ls
| _ -> let xs, ys = split ls
let xs', ys' = mergeSort xs, mergeSort ys
merge(xs', ys')
To add a more simple but naive alternative to pad's:
let rec merge x y =
match (x, y) with
| ([], []) -> []
| ([], rest) -> rest
| (rest, []) -> rest
| (fx :: xs, fy :: _) when fx <= fy -> fx :: merge xs y
| (fx :: _, fy :: ys) -> fy :: merge x ys
Similarly to pad's, we're pattern matching over the function parameters.
I first put them into a tuple so that I can pattern match them both at the same time.
I then take care of the base cases with both or either of the parameters being empty.
I then use when guard to check which first item is smaller
I finally take the first item and cons it to the result of another call to merge with the rest of the items the smaller item was taken from and the whole of the other list. So if the first item of x is smaller, I append the first item of x (fx in this case) to the result of a call to merge passing in the rest of x (xs) and the whole of y (because the first item of y was larger).
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
I have a simple f# quick sort function defined as:
let rec qsort(xs:List<int>) =
let smaller = xs |> List.filter(fun e -> e < xs.Head)
let larger = xs |> List.filter(fun e -> e > xs.Head)
match xs with
| [] -> []
| _ -> qsort(smaller)#[xs.Head]#qsort(larger)
Is there a way in f# to write it more like Haskell:
qsort :: [Int] -> [Int]
qsort [] = []
qsort (x:xs) =
qsort smaller ++ [x] ++ qsort larger
where
smaller = [a | a <- xs, a <= x]
larger = [b | b <- xs, b >= x]
I know the f# algorithm is missing a <= and >=. The question is more about syntax/readibility.
Thanks.
This is the most 'Haskellian' way I can think of, the only thing missing is being able to declare smaller/larger as a 'where' clause:
let rec qsort:int list -> int list = function
| [] -> []
| x::xs -> let smaller = [for a in xs do if a<=x then yield a]
let larger = [for b in xs do if b>x then yield b]
qsort smaller # [x] # qsort larger
I know it's not part of your question, but I'd use List.partition to split the list in smaller/larger in a single pass:
let rec qsort = function
| [] -> []
| x::xs -> let smaller,larger = List.partition (fun y -> y<=x) xs
qsort smaller # [x] # qsort larger
You want your second match clause to be x :: xs, and to use the # (append) operator where your Haskell example uses ++:
let rec qsort xs =
match xs with
| [] -> []
| x :: xs ->
let smaller = qsort (xs |> List.filter(fun e -> e <= x))
let larger = qsort (xs |> List.filter(fun e -> e > x))
smaller # [x] # larger
It's not quite the same as the Haskell definition by cases syntax, but hopefully similar enough for you!
...Or you could make a tail recursive qsort by using CPS:
let qSort lst =
let rec qs l cont =
match l with
| [] -> cont []
| (x::xs) -> qs (List.filter (fun e -> e <= x) xs) (fun smaller ->
qs (List.filter (fun e -> e > x) xs) (fun larger ->
smaller # (x :: larger) |> cont))
qs lst id
This seems to be as concise as it can get (combining the ideas from other answers, and using currying for operators):
let rec qsort = function
| [] -> []
| (x:int) :: xs ->
let smaller = List.filter ((>=) x) xs
let larger = List.filter ((<) x) xs
qsort smaller # [x] # qsort larger
haskell 'where' syntax, which lets you use the name of a function before its definition, kind of maps to f# 'let rec ... and'
let qsort xs =
let rec sort xs =
match ls with
|[] -> ....
|h::t -> (smaller t) # h # (larger t)
and smaller ls = //the 'and' lets you define the
// function after where it is used,
// like with 'where' in haskell
... define smaller in terms of sort
and larger ls =
... same
sort xs
let rec QuickSort l =
match l with
| [] -> []
| _ -> QuickSort([for e in l do if e < (List.head l) then yield e]) #[(List.head l)]# QuickSort([for e in l do if e > (List.head l) then yield e])
Don't forget that List has a partition method, so
let rec quicksort ls =
match ls with
| [] -> []
| h :: t -> let fore, aft = List.partition (fun i -> i < h) t
(quicksort fore) # (h :: quicksort aft)
I had done some analysis of sorting algorithms in F# a few years ago in a very imperative style; I was trying to beat the .NET stock implementation, and managed to do so here. Went to make the following reply to myself today, but FPish won't let me create an account. Argh! Gotta make my post somewhere, and here's as good as anywhere, lol...
While reading "Learn You a Haskell For Great Good" yesterday, the author set up an example for implementing quicksort. The description was quite clear and even before I got to the sample code, an elegant recursive solution (in Haskell) popped into my head. Guess I had never really had an intuitive feel for how quicksort does its thing, because the trivial solution is quite easy, if not very efficient.
Here is my version in F#:
let rec quicksort = function
| [] -> []
| pivot :: xs ->
(left pivot xs) # pivot :: (right pivot xs)
and left pivot xs = quicksort [ for x in xs do if x <= pivot then yield x ]
and right pivot xs = quicksort [ for x in xs do if x > pivot then yield x ]
And, the equivalent Haskell (I like this one... clean!):
quicksort :: Ord a => [a] -> [a]
quicksort [] = []
quicksort (pivot : xs) =
left ++ pivot : right
where
left = quicksort [ x | x <- xs, x <= pivot ]
right = quicksort [ x | x <- xs, x > pivot ]
For grins, here's another F# version (mostly tail-recursive) that's about 2x the speed of the trivial version. Haven't bothered to time this against my original post, though, so no idea how it stacks up to the mutable version in my OP on FPish.net (FSHub) from a few years ago...
let rec quicksort' xs =
let rec aux pivot left right = function
| [] -> (quicksort' left) # pivot :: (quicksort' right)
| x :: xs ->
if x <= pivot then
aux pivot (x :: left) right xs
else
aux pivot left (x::right) xs
match xs with
| [] -> []
| x :: xs -> aux x [] [] xs
I need to generate permutations on a given list. I managed to do it like this
let rec Permute (final, arr) =
if List.length arr > 0 then
for x in arr do
let n_final = final # [x]
let rest = arr |> List.filter (fun a -> not (x = a))
Permute (n_final, rest)
else
printfn "%A" final
let DoPermute lst =
Permute ([], lst)
DoPermute lst
There are obvious issues with this code. For example, list elements must be unique. Also, this is more-less a same approach that I would use when generating straight forward implementation in any other language. Is there any better way to implement this in F#.
Thanks!
Here's the solution I gave in my book F# for Scientists (page 166-167):
let rec distribute e = function
| [] -> [[e]]
| x::xs' as xs -> (e::xs)::[for xs in distribute e xs' -> x::xs]
let rec permute = function
| [] -> [[]]
| e::xs -> List.collect (distribute e) (permute xs)
For permutations of small lists, I use the following code:
let distrib e L =
let rec aux pre post =
seq {
match post with
| [] -> yield (L # [e])
| h::t -> yield (List.rev pre # [e] # post)
yield! aux (h::pre) t
}
aux [] L
let rec perms = function
| [] -> Seq.singleton []
| h::t -> Seq.collect (distrib h) (perms t)
It works as follows: the function "distrib" distributes a given element over all positions in a list, example:
distrib 10 [1;2;3] --> [[10;1;2;3];[1;10;2;3];[1;2;10;3];[1;2;3;10]]
The function perms works (recursively) as follows: distribute the head of the list over all permutations of its tail.
The distrib function will get slow for large lists, because it uses the # operator a lot, but for lists of reasonable length (<=10), the code above works fine.
One warning: if your list contains duplicates, the result will contain identical permutations. For example:
perms [1;1;3] = [[1;1;3]; [1;1;3]; [1;3;1]; [1;3;1]; [3;1;1]; [3;1;1]]
The nice thing about this code is that it returns a sequence of permutations, instead of generating them all at once.
Of course, generating permutations with an imperative array-based algorithm will be (much) faster, but this algorithm has served me well in most cases.
Here's another sequence-based version, hopefully more readable than the voted answer.
This version is similar to Jon's version in terms of logic, but uses computation expressions instead of lists. The first function computes all ways to insert an element x in a list l. The second function computes permutations.
You should be able to use this on larger lists (e.g. for brute force searches on all permutations of a set of inputs).
let rec inserts x l =
seq { match l with
| [] -> yield [x]
| y::rest ->
yield x::l
for i in inserts x rest do
yield y::i
}
let rec permutations l =
seq { match l with
| [] -> yield []
| x::rest ->
for p in permutations rest do
yield! inserts x p
}
It depends on what you mean by "better". I'd consider this to be slightly more elegant, but that may be a matter of taste:
(* get the list of possible heads + remaining elements *)
let rec splitList = function
| [x] -> [x,[]]
| x::xs -> (x, xs) :: List.map (fun (y,l) -> y,x::l) (splitList xs)
let rec permutations = function
| [] -> [[]]
| l ->
splitList l
|> List.collect (fun (x,rest) ->
(* permute remaining elements, then prepend head *)
permutations rest |> List.map (fun l -> x::l))
This can handle lists with duplicate elements, though it will result in duplicated permutations.
In the spirit of Cyrl's suggestion, here's a sequence comprehension version
let rec permsOf xs =
match xs with
| [] -> List.toSeq([[]])
| _ -> seq{ for x in xs do
for xs' in permsOf (remove x xs) do
yield (x::xs')}
where remove is a simple function that removes a given element from a list
let rec remove x xs =
match xs with [] -> [] | (x'::xs')-> if x=x' then xs' else x'::(remove x xs')
IMHO the best solution should alleviate the fact that F# is a functional language so imho the solution should be as close to the definition of what we mean as permutation there as possible.
So the permutation is such an instance of list of things where the head of the list is somehow added to the permutation of the rest of the input list.
The erlang solution shows that in a pretty way:
permutations([]) -> [[]];
permutations(L) -> [[H|T] H<- L, T <- permutations( L--[H] ) ].
taken fron the "programming erlang" book
There is a list comprehension operator used, in solution mentioned here by the fellow stackoverflowers there is a helper function which does the similar job
basically I'd vote for the solution without any visible loops etc, just pure function definition
I'm like 11 years late, but still in case anyone needs permutations like I did recently. Here's Array version of permutation func, I believe it's more performant:
[<RequireQualifiedAccess>]
module Array =
let private swap (arr: _[]) i j =
let buf = arr.[i]
arr.[i] <- arr.[j]
arr.[j] <- buf
let permutations arr =
match arr with
| null | [||] -> [||]
| arr ->
let last = arr.Length - 1
let arr = Array.copy arr
let rec perm arr k =
let arr = Array.copy arr
[|
if k = last then
yield arr
else
for i in k .. last do
swap arr k i
yield! perm arr (k + 1)
|]
perm arr 0