glirc-2.40: src/ContextFilter.hs
module ContextFilter (filterContext) where
-- | Like 'filter' except you can request the elements before
-- and after the matched elements.
--
-- >>> filterContext 2 1 (\x -> 4<=x&&x<=6) [0..10::Int]
-- [2,3,4,5,6,7]
--
-- >>> filterContext 2 1 even [0..10::Int]
-- [0,1,2,3,4,5,6,7,8,9,10]
--
-- >>> filterContext 2 1 (==10) [0..10::Int]
-- [8,9,10]
--
-- >>> filterContext 2 1 (==0) [0..10::Int]
-- [0,1]
--
-- >>> filterContext 0 0 (==0) [0..10::Int]
-- [0]
--
-- >>> filterContext 2 1 (==5) [0..10::Int]
-- [3,4,5,6]
--
-- >>> filterContext 1 2 (==5) [0..10::Int]
-- [4,5,6,7]
filterContext ::
Int {- ^ context before -} ->
Int {- ^ context after -} ->
(a -> Bool) {- ^ predicate -} ->
[a] {- ^ inputs -} ->
[a] {- ^ matches with context -}
filterContext before after p xs0
| before < 0 = error "filterContext: bad before"
| after < 0 = error "filterContext: bad after"
| otherwise = go 0 0 xs0 xs0
where
width = before + after
-- i: index
-- m: current match window
-- xs: list to match
-- ys: offset list to generate results from
go i m (x:xs) yys@(y:ys) =
if (m > 0 || px) && i >= before then y : rest else rest
where
rest = go (i+1) m' xs ys'
px = p x
m' = max (m-1) (if px then width else 0)
ys' = if i >= before then ys else yys
-- no more matches, so just return the remaining m window
go _ m _ ys = take m ys