#sorting #haskell
#сортировка #haskell
Вопрос:
Есть ли вариант
sortBy :: (a -> a -> Ordering) -> [a] -> [a]
(в Data.List) это позволяет мне использовать a -> a -> Maybe Ordering
функцию сортировки вместо a -> a -> Ordering
?
Что этот вариант будет делать, так это:
sortBy' :: (a -> a -> Maybe Ordering) -> [a] -> Maybe [a]
Если a -> a -> Maybe Ordering
когда-либо возвращается Nothing
, когда он вызывается во время сортировки, sortBy'
вернется Nothing
. В противном случае он вернет отсортированный список, завернутый в Just
.
Если такой вариант еще не доступен, не могли бы вы помочь мне его создать? (Предпочтительно тот, который, по крайней мере, так же эффективен, как sortBy
.)
Комментарии:
1. Я не думаю, что это хорошая идея. Будет ли результат
Nothing
зависеть от того, какие сравнения выполняются, и какие сравнения выполняются, будет зависеть от того, какой алгоритм сортировки используется. Чтобы проверить, что все возможные сравненияJust
будут, потребуется O (n ^ 2) времени.2. Я думаю, было бы полезно, если бы вы описали нам, чего вы пытаетесь достичь с помощью этого. Почему бы просто не убедиться, что вы передаете действительные данные
sortBy
заранее? Имеется ли в виду вариант использования? Если вы сделаете это, мы сможем помочь лучше.3. Я мог бы представить себе использование такой функции для топологической сортировки, где, если возвращаемое значение было
Nothing
, вы могли бы произвольно выбрать одно или другое, чтобы прийти первым. Но в этом случае вы могли бы с таким же успехом использовать функцию returnLT
вместоNothing
, и все равно использоватьsortBy
.4. @chepner, разве ты не можешь все испортить, пытаясь выполнить подобную топологическую сортировку? Вы могли бы сделать вывод
x<y
и позжеy<x
.5. @leftaroundabout @Cirdec Я думаю, что достаточно иметь транзитивность: т.Е. Всякий раз, когда два сравнения
x<y,y<z
завершаются успешно (isJust
) сLT
, тогда сравнениеx<z
должно завершиться успешно сLT
(то же самое дляGT,EQ
, включая смешанные случаи). Когда это произойдет и сортировка вернетсяJust
, выполняемых сравненийsort
должно быть достаточно, чтобы гарантировать, что сравнение всегда будет успешным.
Ответ №1:
Вы можете адаптировать быструю сортировку :
quickSortBy :: (a -> a -> Maybe Ordering) -> [a] -> Maybe [a]
quickSortBy f [] = Just []
quickSortBy f (x:xs) = do
comparisons <- fmap (zip xs) $ mapM (f x) xs
sortLesser <- quickSortBy f . map fst $ filter ((`elem` [GT, EQ]) . snd) comparisons
sortUpper <- quickSortBy f . map fst $ filter ((== LT) . snd) comparisons
return $ sortLesser [x] sortUpper
По крайней мере, предположим, что ваш предикат сортировки f :: a -> a -> Maybe Ordering
является антисимметричным: f x y == Just LT
тогда и только тогда, когда f y x == Just GT
. Затем, когда quickSortBy f
возвращается Just [x1,...,xn]
, я думаю, у вас есть такая гарантия: для всех i в [1 ..n-1] f xi x(i 1)
равно Just LT
or Just EQ
.
Когда, в частности, f является частичным порядком (транзитивным), то [x1, …,xn] полностью упорядочен.