Say I have two lists:
let a = [1 .. 1000]
let b = [250 .. 500]
How do I get a new list that contains the values {1-249, 501-1000}?
If you're working against the 3.5 framework or higher you could do the following
let c = System.Linq.Enumerable.Except(a,b)
It's not a pure F# solution but it gets the job done. The return will be an instance of IEnumerable<int> though and not an F# list.
Since your list is sorted, you can solve this in linear time using this (non-tail recursive) function:
let rec except a b =
match (a, b) with
| [], x | x, [] -> x
| x::xs, y::ys ->
if x < y then x :: except xs (y::ys)
elif x > y then y :: except (x::xs) ys
else except xs ys
Tail-recursive version:
let rec except_tail_recursive a b =
let rec loop acc a b =
match (a, b) with
| [], x | x, [] -> (List.rev acc) @ x
| x::xs, y::ys ->
if x < y then loop (x::acc) xs (y::ys)
elif x > y then loop (y::acc) (x::xs) ys
else loop acc xs ys
loop [] a b
If you want a pure F# solution, your options will vary based on your requirements. If your lists don't contain duplicated items and you don't care about the order of your output, you can just do:
(Set.of_list a) - (Set.of_list b) |> Set.to_list
If you know that your items are sorted, this should work and be efficient:
let exclude =
let rec exclude = function
| [],_ -> []
| a,[] -> a
| (x::xs as l),(y::ys as r) ->
if x < y then x :: (exclude (xs, r))
elif x > y then exclude (l, ys)
else exclude (xs, ys)
fun a b -> exclude (a,b)
If you have two lists which may contain duplicates, aren't necessarily sorted, you want results in the order they occured in a, and you don't care about performance, you can do:
a |> List.filter (fun x -> not (List.contains x b))