Haskell: Как отсортировать тип записи по одному атрибуту, если другой совпадает? - PullRequest
0 голосов
/ 04 ноября 2018

Если у меня просто очень простой пользовательский тип данных:

data Person = Person {first_name :: String,
                      last_name :: String
                     } deriving (Ord, Eq, Show)

Если у меня есть список этих типов данных Person, и я хочу отсортировать его по last_name тогда и только тогда, когда first_name совпадает. Но я должен не сортировать first_name. Просто позвоните по следующему, очевидно, не работает.

import Data.Function (on)
import Data.List (sortBy)

sortBy (compare `on` last_name ) persons

Как я могу решить это? Я согласен, что это довольно запутанно. Я хочу, чтобы, если у меня было следующее (это определенно не список пользовательских типов данных, я просто хочу показать это четко)

[("c","d"),("a","c"),("a","a")]

После сортировки хотелось бы получить

[("c","d"),("a","a"),("a","c")]

вместо

 [("a","a"),("a","c"),("c","d")]

Таким образом, идея состоит в том, что первый элемент все еще должен появляться вначале, поскольку он не совпадает с first_name с двумя другими. Это возможно? Спасибо!

1 Ответ

0 голосов
/ 04 ноября 2018

Функция сравнения, которую вы хотите, обрабатывать два значения Person как равные, если их имена разные. Если первые имена совпадают, , затем сравните на основе фамилии.

Поскольку sort в Haskell является стабильным, если элемент a предшествует равному элементу b на входе, он также будет предшествовать b на выходе. В этом случае два элемента с разными именами будут сравниваться как равные, поэтому sort будет действительно сортировать только последовательные подпоследовательности, разделяющие имя.

Возможно, есть разумный способ реализовать это, но функция простого сравнения может выглядеть как

foo :: Person -> Person -> Ordering
foo x y | first_name x /= first_name y = EQ
        | otherwise                   = (comparing last_name) x y

Учитывая people = [ Person "A" "B",Person "Z" "C",Person "Z" "A"], вы можете увидеть разница между sortBy (comparing last_name) и sortBy foo.

> people
[Person {first_name = "A", last_name = "B"},Person {first_name = "Z", last_name = "C"},Person {first_name = "Z", last_name = "A"}]
> sortBy (comparing last_name) people
[Person {first_name = "Z", last_name = "A"},Person {first_name = "A", last_name = "B"},Person {first_name = "Z", last_name = "C"}]
> sortBy foo people
[Person {first_name = "A", last_name = "B"},Person {first_name = "Z", last_name = "A"},Person {first_name = "Z", last_name = "C"}]
...