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

标签 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)比较日期值(因为 Date 显然不是 comparable )

  • 有没有更优雅/Elm-ish 的方式来实现我想要的?

    更新+解决方案

    正如@“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))
    

    最佳答案

    多亏了 |>,一种更像 Elm 风格的方法是组合式的。运算符(operator)。
    elm-ordering库提供了执行此类操作所需的原语,尤其是 Ordering.byFieldOrdering.breakTiesWith职能。

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

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

    关于comparison - 如何比较 Elm 中的多个字段?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/41535288/

    相关文章:

    python 语法中的 Java 主类

    mysql 比较特定日期

    websocket - 在 Elm 中使用 WebSockets 时出现 "input is undefined"错误

    functional-programming - 如何在 ELM 中重构此功能?

    string - bash 脚本基本字符串比较

    java - 通过哈希比较 java 映射

    c - C 中的十六进制常量是无符号的,即使 L 后缀

    elm 语言服务器不支持 neovim

    html - 在 Elm 中为样式元素 (v5) 分配 id

    haskell - 如何在 Elm(或 Haskell)中的函数之间共享数据