В настоящее время я пишу веб-словарь для лексики в Вяз. Это требует сортировки списка слов с помощью пользовательского компаратора.Как сравнить несколько полей в 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)
Мои правила для сравнения (в порядке убывания значимости):
- количество правильных догадок (по возрастанию)
- номер общие догадки (по убыванию)
- , когда слово было последним спросил (по возрастанию)
- при добавлении слова (по убыванию)
Лучший подход, который я мог придумать это:
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/вяза дата-формате) -с ompare Значения даты (начиная с даты, по-видимому, неcomparable
)
Есть ли более элегантный/способ вязания для достижения того, чего я хочу?
Update + решение
Как @ "Зимм 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))
Отлично! Я добавил соответствующую часть вашего решения на свой вопрос, чтобы избежать зависимости от runelm.io - или вы предпочли бы соответственно обновить текст ответа? –