[英]Check a list if sorted in ascending or descending or not sorted in haskell?
我是Haskell的新手。 我刚刚学习了Haskell两个星期。 我不太了解if else语句和haskell的列表理解如何工作。 所以我想做一个可以弄清楚排序类型的函数,例如列表按升序或降序排序,或者根本不排序。 我知道如何检查列表是否按升序和降序排列,但我不知道如何检查列表是否没有按排序。
data SortType = Ascending | Descending | NotSorted deriving (Show)
sorted :: (Ord a) => [a] -> TypeOfSort
sorted [] = Ascending
sorted [x] = Ascending
sorted (x:y:xs) | x < y = sorted (y:xs)
| otherwise = Descending
sorted_ = Ascending
如果有人可以告诉我该怎么做,那将是一个很大的帮助。 谢谢。 P / s:这不是家庭作业/工作资料,而是我想学习的东西。
您的功能中有问题的部分是| otherwise = Descending
| otherwise = Descending
。 根据您的函数定义,如果列表中有两个连续的示例,使得x >= y
,则该函数为降序 。 这不是True
:如果对于所有两个连续元素x > y
(或者如果不要求它严格降序,则x >= y
则函数正在降序。
此外,这里的另一个问题是具有一个元素(或没有元素)的列表可以被视为Ascending
和Descending
。 所以我认为我们要做的第一件事是定义一些语义。 我们可以决定使输出成为TypeOfSort
项的列表,或者我们可以决定扩展TypeOfSort
的选项TypeOfSort
。
在这个答案中,我将选择最后一个选项。 我们可以将TypeOfSort
扩展为:
data TypeOfSort = Ascending | Descending | Both | NotSorted
deriving (Show)
现在我们可以处理函数本身。 这里的基本情况当然是空列表[]
和带有一个元素[_]
的列表:
sorted [] = Both
sorted [_] = Both
现在我们需要定义归纳案例。 列表何时排序? 如果所有元素都(严格)大于前一个元素。 如果所有元素都(严格地)比前一个元素小,则列表将以降序排序。 现在让我们假设严谨 。 以后很容易更改功能定义。
因此,如果我们有一个包含两个或多个元素的列表,则以第二个元素开头的列表为Ascending
或Both
且x < y
,换句话说,该列表为Ascending
:
sorted (x:y:xs) | Both <- sort_yxs, x < y = Ascending
| Ascending <- sort_yxs, x < y = Ascending
where sort_yxs = sorted (y:xs)
降序也是如此:如果列表的其余部分按降序排列,并且第一个元素大于第二个元素,则列表按降序排列:
| Both <- sort_yxs, x > y = Descending
| Ascending <- sort_yxs, > y = Descending
where sort_yxs = sorted (y:xs)
在其余所有情况下,这意味着列表的某些部分Ascending
而某些部分则Descending
,因此列表为NotSorted
。
| otherwise = NotSorted
或将所有这些放在一起:
sorted [] = Both
sorted [_] = Both
sorted (x:y:xs) | Both <- sort_yxs, x < y = Ascending
| Ascending <- sort_yxs, x < y = Ascending
| Both <- sort_yxs, x > y = Descending
| Ascending <- sort_yxs, x > y = Descending
| otherwise = NotSorted
where sort_yxs = sorted (y:xs)
TypeOfSort
为Monoid
上面的定义包含很多边缘情况,这使得编写简单的程序变得困难。 通过引入一些实用程序功能,我们可以使其变得更容易。 例如,可以通过定义一个接受两个TypeOfSort
并返回交集的函数来完成此操作。 这样的功能看起来像:
intersect Both x = x
intersect x Both = x
intersect Ascending Ascending = Ascending
intersect Descending Descending = Descending
intersect _ _ = NotSorted
实际上, Both
形成了一个以Both
为标识元素的monoid :
instance Monoid where
mappend Both x = x
mappend x Both = x
mappend Ascending Ascending = Ascending
mappend Descending Descending = Descending
mappend _ _ = NotSorted
mempty = Both
现在我们可以将定义重写为:
sorted [] = Both
sorted [_] = Both
sorted (x:y:ys) | x > y = mappend rec Ascending
| x < y = mappend rec Descending
| otherwise = NotSorted
where rec = sorted (y:ys)
我的解决方案不使用排序功能,也没有递归:
data SortType = Ascending | Descending | NotSorted | Flat | Unknown deriving (Show)
sorted :: (Ord a) => [a] -> SortType
sorted [] = Unknown
sorted [a] = Flat
sorted xs
| and [x == y | (x, y) <- zipPairs xs] = Flat
| and [x <= y | (x, y) <- zipPairs xs] = Ascending
| and [x >= y | (x, y) <- zipPairs xs] = Descending
| otherwise = NotSorted
zipPairs :: [a] -> [(a, a)]
zipPairs xs = zip xs (tail xs)
使用lambda的人可能更快
all (\(x, y) -> x <= y) (zipPairs xs)
在Python中,我可能会做这样的事情
from itertools import izip, islice
n = len(lst)
all(x <= y for x, y in izip(islice(lst, 0, n - 1), islice(lst, 1, n)))
我想您也可以按照以下步骤进行:
data Sorting = Why | Karma | Flat | Descent | Ascent deriving (Show)
howSorted :: Ord a => [a] -> Sorting
howSorted xs | xs == [] = Why
| all (== head xs) $ tail xs = Flat
| and $ map (uncurry (<=)) ts = Ascent
| and $ map (uncurry (>=)) ts = Descent
| otherwise = Karma
where ts = zip xs $ tail xs
我们已经从Data.List中实现了sort的实现,可以用来实现此目的。
import Data.List (sort)
sorted xs
| sort xs == xs = Ascending
| reverse (sort xs) == xs = Descending
| otherwise = NotSorted
如果排序后的列表等于列表,则必须使用升序排序。
如果反向排序的列表等于该列表,则必须使用降序排序。
否则,不进行排序。
正如@ Benjamin-Hodgson指出的那样,可能需要考虑边缘条件。 使用此实现,一个空列表计为已排序,一个项目的列表也是如此,重复的同一项目的列表也是如此。
用法:
λ> sorted [1..5]
Ascending
λ> sorted [5,4..1]
Descending
λ> sorted [1,3,1]
NotSorted
λ> sorted []
Ascending
λ> sorted [1]
Ascending
λ> sorted [1,1,1]
Ascending
或者,我们可以将sortBy用于相反的情况,以避免必须完全反转列表。 这只是按默认的比较功能排序,且参数已翻转,因此小于小于变为大于大于。
import Data.List (sort, sortBy)
sorted xs
| sort xs == xs = Ascending
| sortBy (flip compare) xs == xs = Descending
| otherwise = NotSorted
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.