2012-03-24 2 views
4

하스켈에서 다음 코드를 작성하는 더 좋고 더 간결한 방법이 있습니까? 나는 if..else을 사용하여 시도했지만 다음보다 읽기 쉽지 않습니다. 나는 xs리스트 (이것은 엄청납니다!)를 8 번 지나서 8 개의 그룹으로 분리하는 것을 피하기를 원합니다. groupByData.List은 하나의 테스트 조건 함수, 즉 (a -> a -> Bool) -> [a] -> [[a]]만을 취합니다.여러 개의 테스트 함수를 가진 groupBy

x1 = filter (check condition1) xs 
x2 = filter (check condition2) xs 
x3 = filter (check condition3) xs 
x4 = filter (check condition4) xs 
x5 = filter (check condition5) xs 
x6 = filter (check condition6) xs 
x7 = filter (check condition7) xs 
x8 = filter (check condition8) xs 
results = [x1,x2,x3,x4,x5,x6,x7,x8] 

답변

5

이 한 번만 목록을 통과 쓸 수 번만 목록을 통과 한 고집 경우

import Data.Functor 
import Control.Monad 

filterN :: [a -> Bool] -> [a] -> [[a]] 
filterN ps = 
    map catMaybes . transpose . 
    map (\x -> map (\p -> x <$ guard (p x)) ps) 

목록의 각 요소에 대해 mapMaybe, 각각의 목록을 생성합니다 하나의 술어에 대응하는; 요소가 술어를 만족하지 않으면 Nothing이거나 술어를 충족시키는 경우 Just x입니다. 그런 다음 transpose은 목록이 요소가 아닌 술어로 구성되고 모든 요소가 목록을 구성하고, map catMaybes은 술어를 만족하지 않는 요소의 항목을 버리지 않도록 이러한 모든 목록을 섞습니다.

일부 설명 : x <$ mfmap (const x) m이며, Maybe를 들어, guard bif b then Just() else Nothing, 그래서 x <$ guard bif b then Just x else Nothing입니다.

mapmap (\x -> [x <$ guard (p x) | p <- ps])으로 작성할 수도 있습니다.

+0

Landei의 답변이 더 효율적이라고 생각하지만 매우 우아합니다. – is7s

+0

나는 그렇게 확신하지 않는다. 처음에는 Landei 's가 무엇인가하기 전에 전체 목록을 뒤집습니다. – ehird

+0

다른 토론 후 다른 곳에서 더 좋은 구현 방법을 생각해 냈습니다. 내 대답을 업데이트했습니다. – ehird

2

난 당신이 GHC.Exts에서 groupWith를 사용할 수 있습니다 생각합니다.

당신이 xs의 '클래스'의 모든 요소를 ​​할당 할 a -> b 기능을 작성하는 경우, 내가 groupWith 한 번만 목록을 통과, 당신이에 원하는 방식으로 xs을 분할 할 보라.

3
map (\ cond -> filter (check cond) xs) [condition1, condition2, ..., condition8] 
+0

이 호출되어야 목록 uppdate 각 값에 대해 이동합니다 각 조건에 대해 목록을 다시 트래버스하고 있습니다. – vis

+2

그러나 복잡한 함수가있는 하나의 순회보다 간단한 함수가 여러 순회가 느립니까? – augustss

+0

오, 절대적으로. 그것은 작동하는 것 중 가장 단순한 것입니다. –

1

groupBy 실제로 원하는 것을 수행하지 않습니다. 여러 술어 기능을 허용하더라도 목록에 대한 필터링은 수행하지 않습니다. 그것은 단지 어떤 조건을 만족시키는리스트 엘리먼트의 인접한 런을 함께 묶는다. 필터 조건이 결합 된 경우에도 제공된 목록의 모든 요소를 ​​포함한다고해도 이는 여전히 다른 작업입니다. 예를 들어 groupBy은 목록 요소의 순서를 수정하지 않으며 결과에서 주어진 요소를 두 번 이상 포함 할 가능성이 없으며 작업에서 두 ​​가지 작업을 모두 수행 할 수 있습니다. , nietaki의 대답에 부록으로

> filterMulti [(<2), (>=5)] [2, 5, 1, -2, 5, 1, 7, 3, -20, 76, 8] 
[[1, -2, 1, -20], [5, 5, 7, 76, 8]] 
+0

이것은 우아한 해결책처럼 보이지만 각 조건에 대해 매번 목록을 횡단하지 않는지 확인할 수 있습니다. – vis

+0

매번 목록을 탐색하지만 질문에서 지정한 예제도 마찬가지입니다. 같은 목록을 여러 번 탐색하지 않고 여러 번 필터링 할 수는 없습니다. – bitbucket

+0

필자는 "요소를 8 개의 그룹으로 분리"하여 목록을 필터링 할 필요가 없으며 요소를 생략하지 않고 별도의 그룹으로 분할합니다. – nietaki

1

(이 코멘트해야을하지만 너무 오래입니다 : 예를 들어

import Control.Applicative 

filterMulti :: [a -> Bool] -> [a] -> [[a]] 
filterMulti ps as = filter <$> ps <*> pure as 

:

이 기능은 당신이 찾고있는 무엇을 할 것인가 그래서 그의 대답이 정확하다면, 그의 것을 받아 들여라!), 함수 a -> b은 중첩 된 시리즈 if ... then .. else으로 쓰여질 수있다. 그러나 그것은 매우 관용적 인 하스켈이 아니며 확장 성이 매우 뛰어나다. 이것은 약간 더 나은 수 있습니다 :

import Data.List (elemIndex) 
import GHC.Exts (groupWith) 

f xs = groupWith test xs 
    where test x = elemIndex . map ($ x) $ [condition1, ..., condition8] 

그것은 최초의 condition_이 만족하여 각 요소를 분류하고 (그리고 자신의 범주에 어떤을 만족하지 않는 사람들을 둔다).

은 (elemIndex에 대한 문서는 here입니다.)

4

당신이, 당신이

filterMulti :: [a -> Bool] -> [a] -> [[a]] 
filterMulti fs xs = go (reverse xs) (repeat []) where 
    go [] acc = acc 
    go (y:ys) acc = go ys $ zipWith (\f a -> if f y then y:a else a) fs acc 
1

첫 번째 함수는 "uppdated"목록의 목록을 반환하고 두 번째 기능은 전체 목록을 통해

myfilter :: a -> [a -> Bool] -> [[a]] -> [[a]] 
myfilter _ [] [] = [] 
myfilter x f:fs l:ls | f x  = (x:l): Myfilter x fs ls 
        | otherwise = l:Myfilter x fs ls 


filterall :: [a] -> [a -> Bool] -> [[a]] -> [[a]] 
filterall [] _ l = l 
filterall x:xs fl l:ls = filterall xs fl (myfilter x fl l) 

filterall xs [condition1,condition2...] [[],[]...]

+0

하스켈의 함수 이름은 대문자로 시작할 수 없다는 것을 잊지 마십시오. – Vitus

관련 문제