Фильтрация списка в Хаскеле - PullRequest
2 голосов
/ 13 октября 2010

Я пытаюсь начать изучать haskell, и возник вопрос. Скажи, у меня есть функция

countFilter :: (a -> Bool) -> [a] -> ([a], Int)
countFilter a z = case z of []        -> ([], 0);
                            (x:xs)    -> (filter a z , length (filter a z))

Возвращает список, все элементы которого относятся к определенному предикату, и длина этого списка, который не имеет значения.

countFilter (<7) [1,2,4,7,11,8,2] выведет ([1,2,4,2], 4).

Как создать такой вывод: ([7,11,8], 4) с использованием того же предиката (<7)? </p>

1 Ответ

5 голосов
/ 13 октября 2010

Если я правильно понимаю ваш вопрос, вы хотите вернуть все элементы, которые не соответствуют предикату (< 7) в качестве первого элемента пары.

В этом случае вы можете просто использовать функцию not, чтобы перевернуть полученное логическое значение.
То есть создайте новый предикат (\x -> not (oldPred x)), или используя состав функции: (not . oldPred):

countFilter :: (a -> Bool) -> [a] -> ([a], Int)
countFilter f xs = (filter (not . f) xs, length (filter f xs))

Обратите внимание, что и filter, и length могут работать с пустыми списками, поэтому вам не нужно писать case самостоятельно.


В качестве альтернативы, вы можете использовать функцию partition для создания двух списков, чтобы вы не фильтровали список дважды:

import Data.List

countFilter :: (a -> Bool) -> [a] -> ([a], Int)
countFilter f xs = let (ys, zs) = partition (not . f) xs
                   in (ys, length zs)

Возможно, возможно создать еще более эффективную версию, которая не использует length, но я оставляю это как упражнение: -)

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...