Remove elements at positions n and n-1 in a Haskell list, when n fits a predicate

让人想犯罪 __ 提交于 2020-01-06 12:44:07

问题


Say I have a list of all the integers from 2 to 20.

[2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20]

I also have a function f x that returns either True or False. When I apply this function to the element at position n and it equals to True, I want to remove it and its precedent element (which is the element at position n-1). I want to keep doing this until the list is empty of elements for which the function equals to True, as well as their preceding elements.

Example: Let's say that the element at position 11, which equals to 13, fits the predicate. I then want to remove the element at position 10, which equals to 12, as well. After that my final list would be:

[2,3,4,5,6,7,8,9,10,11,14,15,16,17,18,19,20]

Let's also say that the elements at position 4, 8 as well as 15 are the only elements (apart from the element at position 13) that fit the predicate. After removing them and their preceding elements my final list would look like:

[2,3,4,7,8,11,14,15,18,19,20]

I'm an inexperienced Haskell programmer, and just playing around for fun. I thought of using some kind of lambda function as predicate to a filter, or creating a function like listRemove xs ys that removes all elements of xs that are also an element of ys, but I feel kind of lost on both.

Any help would be appreciated!

EDIT: what I am trying to do is to solve a Project Euler problem, namely #179. The predicate f x is to check whether x is a prime number or not. Therefore I can surely say that no corner cases exists – e.g. there are no cases such as [x, x, t, t] where t is a number for which the predicate holds, since there exists no two consecutive integers that are both prime except for 2 and 3, which I can easily handle in my solution. Instead, the closest you can get is [x, t, x, t], and in that case I want to remove all of those elements.


回答1:


Solved "Remove elements at positions n and n-1 in a Haskell list, when n fits a predicate"

filter' :: (a -> Bool) -> [a] -> [a]
filter' f xs = map (\i -> xs!!i) $
                 [i | i <- [0 .. s], fit i && (i >= s || fit (i+1))]
               where s = length xs - 1
                     fit i = not (f (xs!!i))

usage

*Main> filter' (==4) [1,2,3,4,5,6]
[1,2,5,6]

*Main> filter' (\n -> n `mod` 7 == 0) [1..23]
[1,2,3,4,5,8,9,10,11,12,15,16,17,18,19,22,23]

*Main> filter' (\n -> n `elem` [4,5,6]) [1..10]
[1,2,7,8,9,10]

With O(n) cost may be

filter' :: (a -> Bool) -> [a] -> ([a], Bool)
filter' _  [] = ([], False)
filter' f [x] = if f x then ([], True) else ([x], False)
filter' f (y:xs) = case filter' f xs of
                    (xs', True)  -> (xs', f y)
                    (xs', False) -> if f y then (xs', True) else (y:xs', False)

using standar functions

filter' f xs = filter (not.f) $ map fst $ filter (not.f.snd) $ zip xs $ tail xs ++ [last xs]



回答2:


Assuming you have:

disallowed :: Int -> bool
-- A function that matches your example
disallowed x = elem x [6, 10, 13, 17]

What you want is just

import Data.List (tails)

map head . filter (not . any disallowed . take 2) . filter (not . null) . tails $ [2..20]

If you want to give it a name:

filterWithTails :: ([a] -> Bool) -> [a] -> [a]
filterWithTails f = map head . filter f . filter (not . null) . tails

filterWithTails (not . any disallowed . take 2) [2..20]

(not . any disallowed . take 2) is how you want to filter a list considering the remainder of the list when filtering. It'd be hard to give a better name than the composition of the functions that make it up.



来源:https://stackoverflow.com/questions/21185550/remove-elements-at-positions-n-and-n-1-in-a-haskell-list-when-n-fits-a-predicat

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!