我想按一个属性排序,然后按另一个属性排序(如果第一个属性相同。)
Haskell中组成两个比较函数的惯用方法是什么,即与sortBy
一起使用的函数?
鉴于
f :: Ord a => a -> a -> Ordering
g :: Ord a => a -> a -> Ordering
撰写f
和g
会产生:
h x y = case v of
EQ -> g x y
otherwise -> v
where v = f x y
答案 0 :(得分:51)
vitus为Monoid
指出了非常酷的Ordering
实例。如果你将它与实例instance Monoid b => Monoid (a -> b)
结合起来,那么你的组合函数就是(准备好了):
mappend
检查出来:
Prelude Data.Monoid> let f a b = EQ
Prelude Data.Monoid> let g a b = LT
Prelude Data.Monoid> :t f `mappend` g
f `mappend` g :: t -> t1 -> Ordering
Prelude Data.Monoid> (f `mappend` g) undefined undefined
LT
Prelude Data.Monoid> let f a b = GT
Prelude Data.Monoid> (f `mappend` g) undefined undefined
GT
+1用于强大而简单的抽象
答案 1 :(得分:3)
您可以使用<>
运算符。在此示例中,bigSort
按字符串的数值对字符串进行排序,首先比较长度,然后按字典顺序进行比较。
import Data.List (sortBy)
import Data.Ord (compare, comparing)
bigSort :: [String] -> [String]
bigSort = sortBy $ (comparing length) <> compare
示例:
bigSort ["31415926535897932384626433832795","1","3","10","3","5"] =
["1","3","3","5","10","31415926535897932384626433832795"]
<>
是mappend
中Data.Monoid module
的别名(请参见 jberryman 答案)。
(免费)这本书学到一个Haskell来造福大人!在Chapter 11
中解释了它的工作原理。instance Monoid Ordering where mempty = EQ LT `mappend` _ = LT EQ `mappend` y = y GT `mappend` _ = GT
实例的设置是这样的:当我们
mappend
有两个Ordering
值时,将保留左侧的值,除非左侧的值为EQ
,在这种情况下正确的就是结果。身份为EQ
。