If your lists only contains integers of a limited size, there is also a solution in O(n):
1.) Create an array of booleans of the size of you largest integer value plus 1 in your original lists (e.g. in your example '9+1'); set all fields to false;
let m = Array.create 10 false
-> [|false; false; false; false; false; false; false; false; false; false|]
2.) Iterate over the first list: For every element you encounter, set the boolean with the respective offset to 'true'; in your example this would yield
List.iter (fun x -> m.(x) <- true) e1
-> [|false; false; false; true; true; true; true; true; false; false|]
3.) Filter over the second list, keeping only those elements of which the corresponding field in the array is true
List.filter (fun x -> m.(x) = true) e2
-> [3; 5; 7]
| h3::t3 as l -> h1::l
instead of| h3::t3 -> h1::(h3::t3)
, you may save the compiler the allocation of a new cons cell to create a new list identical to one it already has. The compiler could do this optimization itself, but it probably won't. – Gizmo