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))