2015-02-07 2 views
1

Мне нужна была альтернатива filter, которая вместо того, чтобы отбрасывать ложные случаи, хранит их в отдельном месте. Я придумал ниже, но, к сожалению, он меняет список.Порядок обратного списка без увеличения сложности

Очевидно, я мог бы добавить x в ys или zs вместо cons, но это значительно увеличит сложность.

Есть ли способ сохранить его в порядке, не увеличивая сложность?

splitBy :: (a -> Bool) -> [a] -> ([a],[a]) 
splitBy f xs = splitBy' f xs ([],[]) 
      where 
       splitBy' :: (a -> Bool) -> [a] -> ([a],[a]) -> ([a],[a]) 
       splitBy' _ [] result = result 
       splitBy' f (x:xs) (ys,zs) = if f x then splitBy' f xs (x:ys,zs) 
                else splitBy' f xs (ys,x:zs) 
+5

A [hoogle поиск ] (https://www.haskell.org/hoogle/?hoogle=%28a-%3EBool%29-%3E%5Ba%5D-%3E%28%5Ba%5D%2C%5Ba%5D%29) показывает что эта функция называется 'partition'. –

+0

Спасибо за подсказку, чтобы найти источник и посмотреть, сохраняет ли он их в порядке, не увеличивая сложность. Я новичок в Haskell и не привык искать места, кроме прелюдии. –

+2

[исходный код для 'partition'] (http://hackage.haskell.org/package/base-4.7.0.2/docs/src/Data-List.html#partition): он эффективно добавляет элементы в конец списка, который он строит (оба они). Lazy pattern ('' ') допускает бесконечный список как вход (например,' take 10 $ fst $ partition odd [1 ..] '). –

ответ

3

Как уже говорилось, функция называется partition, и это что-то работает, как этот

partition :: (a -> Bool) -> [a] -> ([a], [a]) 
partition f = foldr (\x ~(yes,no) -> 
         if f x 
         then (x:yes,no) 
         else (yes,x:no)) 
        ([], []) 

за исключением того, что реальная версия добавляет явный xs параметр, возможно, чтобы помочь правила слияния работать должным образом. Если это обалденный матч ленивый шаблон заставляет вас нервничать, вы можете написать это вместо того, чтобы:

partition f = foldr (\x r -> 
         if f x 
         then (x:fst r,snd r) 
         else (fst r,x:snd r)) 
        ([], []) 

Если foldr кажется таинственным для вас, вы можете сделать это следующим образом:

partition f [] = ([], []) 
partition f (x:xs) 
    | f x  = (x:fst r, snd r) 
    | otherwise = (fst r, x:snd r) 
    where r = partition f xs 
+0

вы могли бы использовать '(да, нет)' шаблон в своей последней версии с 'where'. –

+0

@WillNess, это правда, хотя изменение второй версии для соответствия может быть немного неудобным. – dfeuer