Can an F# query expression filter for items that are NOT in a sub-query?

I have the following sample that finds the numbers in s1 that are not in s2.

let s1 = seq { 1..3 }
let s2 = seq { 3..4 }

s1
|> Seq.filter (fun x -> s2 |> Seq.forall (fun y -> x <> y))
|> Seq.iter (fun x -> printfn $"{x}")

This prints 1 and 2 as expected.

Can this also be expressed as a query expression?

>Solution :

First of all, I think your existing solution using filter and forall is perfectly fine and does not need to be converted to query expressions – those are great for SQL-like queries and querying databases, but I think they are often a bit unhelpful for basic sequence processing.

To answer your question, you can do this using a nested query (as in the answer from Violet), but using the all operation:

query { 
  for x in s1 do
  where (query { for y in s2 do all (y > 0) })
  select x }

This is really exactly the same as your original code – the outer query implements filter and the nested query implements forall. You could also freely combine the two:

query { 
  for x in s1 do
  where (Seq.forall (fun y -> x <> y) s2)
  select x }

Although I guess it gets a bit nicer if you turn s2 into a set first:

let s2set = set s2 

query { 
  for x in s1 do
  where (not (s2set.Contains x))
  select x }

Leave a Reply