如何按字符串排序自定义类型

时间:2017-01-10 11:46:47

标签: list sorting haskell

我如何按名字对动物进行分类?名称由String值表示。

data Animal = Cat String | Dog String | Fox String deriving (Show)

testAnimals = [(Dog "c"),(Fox "a"),(Cat "b")]

sortAnimalsByName :: [Animal] -> [Animal]
sortAnimalsByName animals = undefined

查询:

sortAnimalsByName testAnimals

应该返回:

[(Fox "a"),(Cat "b"),(Dog "c")]

我认为应该使用sort :: Ord a => [a] -> [a]中的Data.List函数,但是如何使用?

3 个答案:

答案 0 :(得分:8)

首先,您最好定义一个public class DeviceEnumValidator<T> : PropertyValidator { public DeviceEnumValidator() : base("Invalid Enum value!") { } protected override bool IsValid(PropertyValidatorContext context) { DeviceTypes enumVal= (DeviceTypes) Enum.Parse(typeof(DeviceTypes), context.PropertyValue); if (!Enum.IsDefined(typeof(DeviceTypes), enumVal) return false; return true; } } 函数:

public CheckUpdateVMValidator()
{
    RuleFor(x => x.Device).SetValidator(new DeviceEnumValidator<DeviceTypes>());
}

只需使用sortBy,其中比较器只是compareon animalName

animalName :: Animal -> String
animalName (Cat n) = n
animalName (Dog n) = n
animalName (Fox n) = n

或者你可以 - 像@JonPurdy建议的那样,使用与animalName基本相同的import Data.Function(on) import Data.List(sortBy) sortAnimalsByName :: [Animal] -> [Animal] sortAnimalsByName = sortBy (compare `on` animalName)

comparing

甚至更短:

on compare

如果您使用record-syntax

,则可以进一步省略import Data.Ord(comparing) sortAnimalsByName :: [Animal] -> [Animal] sortAnimalsByName = sortBy (comparing animalName) 的定义
import Data.List(sortOn)

sortAnimalsByName :: [Animal] -> [Animal]
sortAnimalsByName = sortOn animalName

答案 1 :(得分:3)

已编辑感谢@WillemVanOnsem的评论。

首先,这应该是一个正确的和类型,这样你就可以避免重复使用String。意思是,你应该成功

type Animal a = Dog a | Cat a | Fox a

这样你会有一个更普通的动物类型(这是一件好事)。更通用类型的一个优点是它允许您创建更精确的动态类型类实例。

但是在您的情况下,最简单的方法是派生ShowEq,然后像这样写一个Ord实例:

data Animal = Cat String | Dog String | Fox String deriving (Show, Eq)

instance Ord Animal where
  (Cat x) `compare` (Cat y) = x `compare` y
  (Cat x) `compare` (Dog y) = x `compare` y
  (Cat x) `compare` (Fox y) = x `compare` y
  (Dog x) `compare` (Cat y) = x `compare` y
  (Dog x) `compare` (Dog y) = x `compare` y
  (Dog x) `compare` (Fox y) = x `compare` y
  (Fox x) `compare` (Cat y) = x `compare` y
  (Fox x) `compare` (Dog y) = x `compare` y
  (Fox x) `compare` (Fox y) = x `compare` y

data Animal a = Cat a | Dog a | Fox a deriving (Show, Eq)

instance Ord a => Ord (Animal a) where
  (Cat x) `compare` (Cat y) = x `compare` y
  (Cat x) `compare` (Dog y) = x `compare` y
  (Cat x) `compare` (Fox y) = x `compare` y
  (Dog x) `compare` (Cat y) = x `compare` y
  (Dog x) `compare` (Dog y) = x `compare` y
  (Dog x) `compare` (Fox y) = x `compare` y
  (Fox x) `compare` (Cat y) = x `compare` y
  (Fox x) `compare` (Dog y) = x `compare` y
  (Fox x) `compare` (Fox y) = x `compare` y

您可以使用sort,因为现在AnimalOrd个实例

-- sort :: Ord a => [a] -> [a]

sort testAnimals

要点是:使用类型类。这只是简单类型的最简单方法。

答案 2 :(得分:0)

加入@Willem Van Onsem(记录语法)和@urbanslug(实现Ord类实例)给出的答案,我们得到了最简单的答案:

data Animal a = Cat {name :: a}
              | Dog {name :: a}
              | Fox {name :: a} deriving (Show, Eq)

instance Ord a => Ord (Animal a) where
  a1 `compare` a2 = name a1 `compare` name a2

因此可以简单地说

λ> sort [(Dog "c"),(Fox "a"),(Cat "b")]
[Fox {name = "a"},Cat {name = "b"},Dog {name = "c"}]

使用Data.Ord.comparing函数更准确地写一个coud:

instance Ord a => Ord (Animal a) where compare = comparing name