F#: Filter items found in one list from another list

后端 未结 3 620
野趣味
野趣味 2021-01-20 06:57

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}?

相关标签:
3条回答
  • 2021-01-20 07:04

    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.

    0 讨论(0)
  • 2021-01-20 07:14

    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
    
    0 讨论(0)
  • 2021-01-20 07:18

    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))
    
    0 讨论(0)
提交回复
热议问题