A state machine is the appropriate solution here. There are two common ways to implement one:
Hardwired in the form of a set of mutually-recursive functions where the function that is running represents the current state. This can be very efficient but requires tail call elimination, trampolines or goto.
Emulated in the form of a data structure representing the current state and a function of that state and a new input datum that updates the state.
This stuff is the bread and butter of functional programming. Here is an elegant solution to your problem written in the former style in F# and run on your own data set:
> let rec skip = function
| _, yss, [] -> yss
| [_; _; _] as ys, yss, xs -> record ([], ys, yss, xs)
| ys, yss, x::xs when x >= 5 -> skip (x::ys, yss, xs)
| ys, yss, x::xs -> skip ([], yss, xs)
and record = function
| ys', ys, yss, [] -> (ys' @ ys) :: yss
| [_; _], ys, yss, xs -> skip ([], ys :: yss, xs)
| ys', ys, yss, x::xs when x < 3 -> record (x::ys', ys, yss, xs)
| ys', ys, yss, x::xs -> record ([], x::ys' @ ys, yss, xs);;
val skip : int list * int list list * int list -> int list list
val record : int list * int list * int list list * int list -> int list list
> let run xs = skip([], [], xs) |> List.map List.rev |> List.rev;;
val run : int list -> int list list
> run [0;0;0;7;8;0;0;2;5;6;10;11;10;13;5;0;1;0];;
val it : int list list = [[5; 6; 10; 11; 10; 13; 5]]
and here is the same solution written in the latter style:
> type 'a state =
| Skip of 'a list
| Record of 'a list * 'a list;;
type 'a state =
| Skip of 'a list
| Record of 'a list * 'a list
> let rec apply (state, yss) x =
match state, yss with
| Skip([_; _; _] as ys), yss -> apply (Record([], ys), yss) x
| Skip ys, yss when x >= 5 -> Skip(x::ys), yss
| Skip ys, yss -> Skip[], yss
| Record([_; _], ys), yss -> apply (Skip[], ys :: yss) x
| Record(ys', ys), yss when x < 3 -> Record (x::ys', ys), yss
| Record(ys', ys), yss -> Record ([], x::ys' @ ys), yss;;
val apply : int state * int list list -> int -> int state * int list list
> let run xs =
match List.fold apply (Skip [], []) xs with
| Skip _, yss -> yss
| Record(ys', ys), yss -> (ys' @ ys) :: yss
|> List.map List.rev |> List.rev;;
val run : int list -> int list list
> run [0;0;0;7;8;0;0;2;5;6;10;11;10;13;5;0;1;0];;
val it : int list list = [[5; 6; 10; 11; 10; 13; 5]]
Note how the first solution eats the entire input at once whereas the latter bites off a single datum at a time and returns a new state ready to eat another datum. Consequently, the latter is applied to each datum in turn using a fold
and the final half-eaten state must be consumed appropriately before returning.