如何比较Elm中的多个字段?

时间:2017-01-08 17:01:45

标签: comparison elm

我目前正在Elm写一个基于网络的词汇训练师。这需要通过自定义比较器对单词列表进行排序。

我想要排序的类型是:

type alias Word =
  { id: Int
  , sourceWord: String
  , targetWord: String
  , numTries: Int
  , numCorrect: Int
  , createdAt: Maybe Date    -- might be empty, therefore wrapped in Maybe 
  , lastAskedAt: Maybe Date  -- might be empty, therefore wrapped in Maybe
  }

类型别名WordList = List(Word)

我的比较规则是(按重要性降序排列):

  • 正确猜测的数量(asc)
  • 数字总体猜测(desc)
  • 上次询问时(asc)
  • 添加单词时(desc)

我能想出的最佳方法是:

compareWords: Word -> Word -> Basics.Order
compareWords w1 w2 = 
  let
      dateToComparable d = Date.Format.format "%Y-%m-%d" d 
      orderNumCorrect = compare w1.numCorrect w2.numCorrect 
      orderNumTries = compare w2.numTries w1.numTries -- switch ordering to sort descending
      orderLastAskedAt = case (w1.lastAskedAt, w2.lastAskedAt) of
        (Just a1, Just a2) -> compare (dateToComparable a1) (dateToComparable a2)
        (Nothing, Just _)  -> Basics.LT
        (Just _,  Nothing) -> Basics.GT
        (Nothing, Nothing) -> Basics.EQ 
      orderCreatedAt = case (w2.createdAt, w1.createdAt) of -- switch ordering to sort descending
        (Just a1, Just a2) -> compare (dateToComparable a1) (dateToComparable a2)
        (Nothing, Just _)  -> Basics.LT
        (Just _,  Nothing) -> Basics.GT
        (Nothing, Nothing) -> Basics.EQ 
   in
      case orderNumCorrect of
        Basics.EQ -> case orderNumTries of
          Basics.EQ -> case orderLastAskedAt of
            Basics.EQ -> orderCreatedAt
            _ -> orderLastAskedAt
          _ -> orderNumTries 
        _ -> orderNumCorrect

我不喜欢出于以下几个原因:

  • 它很丑陋地狱
  • 它要求我使用Date.Format.format(来自mgold / elm-date-format)来比较日期值(因为日期显然不是comparable

是否有更优雅/榆树的方式来实现我想要的目标?

更新+解决方案

As @" Zimm i48"在他们最优秀的答案中提出,这是一个使用elm-ordering package的更短的版本:

dateToComparable : Maybe Date -> Time
dateToComparable =
    Maybe.map Date.toTime >> Maybe.withDefault 0 

compareWords : Ordering Word
compareWords =
    Ordering.byField .numCorrect
        |> Ordering.breakTiesWith (Ordering.byField (.numTries >> negate))
        |> Ordering.breakTiesWith (Ordering.byField (.lastAskedAt >> dateToComparable))
        |> Ordering.breakTiesWith
            (Ordering.byField (.createdAt >> dateToComparable >> negate))

1 个答案:

答案 0 :(得分:5)

由于|>运算符,更多Elm-ish执行此类操作的方式是在组合上。 elm-ordering库提供了执行此类操作所需的基元,尤其是Ordering.byFieldOrdering.breakTiesWith函数。

关于日期,我的建议是使用Date.toTime(结果值具有可比性)。

奖励:完全实施您可在此处测试的订购功能:https://runelm.io/c/xoz。你可以看到它比你的更简单,更易读......