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]