Home > other >  Filtering a list based on a condition that depends on the value of multiple list elements
Filtering a list based on a condition that depends on the value of multiple list elements

Time:01-25

I have a list in F# that looks like this:

let x = [10; 9; 8; 7; 7; 6; 6; 5; 5; 4; 4; 4; 3; 3; 2; 2; 1; 0; 0; 0; -1; -2; -3]

I need to write a function that returns the elements of the list that come before and including two consecutive 0's. It should return:

[10; 9; 8; 7; 7; 6; 6; 5; 5; 4; 4; 4; 3; 3; 2; 2; 1; 0; 0]

This would be pretty easy to do in a for loop in a non-functional language, but what's the correct functional way to approach this?

CodePudding user response:

If you are learning fp you may prefer to do it directly (theres nothing wrong with doing it directly).

let x = [10; 9; 8; 7; 7; 6; 6; 5; 5; 4; 4; 4; 3; 3; 2; 2; 1; 0; 0; 0; -1; -2; -3]

let rec find : int list -> int list = function
    | 0 :: 0 :: _ -> [ 0; 0 ]
    | head :: tail -> head :: find tail
    | _ -> []

let foo = find x

and get

val foo: int list = [10; 9; 8; 7; 7; 6; 6; 5; 5; 4; 4; 4; 3; 3; 2; 2; 1; 0; 0]

CodePudding user response:

There's no single "correct" solution, but here's one that uses built-in functions instead of recursion:

let snip list =
    list
        |> List.pairwise
        |> List.takeWhile (fun pair ->
             pair <> (0, 0))
        |> List.map fst
        |> fun list' -> list' @ [0; 0]

let x = [10; 9; 8; 7; 7; 6; 6; 5; 5; 4; 4; 4; 3; 3; 2; 2; 1; 0; 0; 0; -1; -2; -3]
snip x
    |> printfn "%A"   // [10; 9; 8; 7; 7; 6; 6; 5; 5; 4; 4; 4; 3; 3; 2; 2; 1; 0; 0]

Or, if you like point-free style, you can do this:

let flip f b a = f a b

let snip =
    List.pairwise
        >> List.takeWhile ((<>) (0, 0))
        >> List.map fst
        >> flip List.append [0; 0]
  • Related