在Haskell中按特定属性对自定义数据类型列表进行排序

Has*_*ell 5 sorting haskell

假设我们有自定义数据类型:

data Person = Person {  first_name :: String,
        last_name :: String,
        age :: Int
        } deriving (Ord, Eq, Show)
Run Code Online (Sandbox Code Playgroud)

我们还说我有这些Person数据类型的列表.我已经创建了一个按顺序对这些人进行排序的函数,但这仅限于每个人的第一个值first_name.我要做的是修改Person数据类型,以便此sort函数按年龄而不是first_name排序(除了交换值顺序以便年龄是第一个).我知道我需要使用instance关键字为Ord 编写自己的比较函数.这就是我被困住的地方.谁能帮我吗?

编辑:是的,这是硬件 - 不幸的是我需要按照我描述的方式来做.

dup*_*ode 18

考虑到有多种有效的方法对Person值进行排序,处理该问题的最简单,最灵活的方法不是通过更改Ord实例,而是通过使用自定义排序功能.

import Data.List (sortBy)
import Data.Ord (comparing)

sortByAge :: [Person] -> [Person]
sortByAge = sortBy (comparing age)
Run Code Online (Sandbox Code Playgroud)

sortBy :: (a -> a -> Ordering) -> [a] -> [a]从比较函数中创建自定义排序函数,同时comparing :: Ord a => (b -> a) -> b -> b -> Ordering给出这样的比较函数,例如,字段acessor.一定要仔细查看所涉及的类型签名,以便了解所有内容是如何组合在一起的.

如果您确实需要更改Ord实例,请按照以下步骤进行操作.语法如下:

instance Ord Person where
    compare = undefined -- placeholder
Run Code Online (Sandbox Code Playgroud)

文档告诉我们,从所有Ord方法中,我们只需要实现compare.现在,我们应该替换undefined什么?我们希望比较基于age,这是一个Int领域.既然Int是一个实例Ord,答案是立竿见影的:

instance Ord Person where
    compare x y = compare (age x) (age y)
Run Code Online (Sandbox Code Playgroud)

顺便提一下,定义comparing是:

comparing :: (Ord a) => (b -> a) -> b -> b -> Ordering
comparing p x y = compare (p x) (p y)
Run Code Online (Sandbox Code Playgroud)

所以我们可以用我们用于第一个解决方案的样式编写实例:

instance Ord Person where
    compare = comparing age
Run Code Online (Sandbox Code Playgroud)