В Haskell, как я могу использовать встроенную функцию sortBy для сортировки списка пар (кортеж)?

Удивительно, если есть лучший способ.

blockquote>

В примере, который вы приводите с массивом, я думаю, что все в порядке.

Если Сериализованная строка содержит данные и объекты, которые вы не хотите выполнять без инициализации (например, создание объектов, которые вы действительно не хотите), вы можете использовать сериализованную библиотеку PHP , которая является полным парсером для сериализованных данных.

Он обеспечивает статический доступ к сериализованным данным на низкоуровневом уровне, поэтому вы можете извлекать только подмножество данных и / или манипулировать сериализованными данными без их инициализации. Однако это слишком много для вашего примера, поскольку у вас есть только массив, и вам не нужно фильтровать / отличать слишком много, я думаю.

37
задан Bruce 3 May 2012 в 18:52
поделиться

5 ответов

Вам нужно построить свою функцию sortGT, чтобы она сравнивала пары так, как вам нужно:

sortGT (a1, b1) (a2, b2)
  | a1 < a2 = GT
  | a1 > a2 = LT
  | a1 == a2 = compare b1 b2


Используя ее, вы получите следующие результаты (я использовал ghci):

*Main Data.List> sortBy sortGT [(1, "b"), (1, "a"), (2, "b"), (2, "a")]
[(2,"a"),(2,"b"),(1,"a"),(1,"b")]
38
ответ дан 27 November 2019 в 04:32
поделиться

Сначала мы должны сделать функцию упорядочения, которая принимает две точки и возвращает либо EQ , LT или GT (т.е. sortGT :: (a, b) -> (a, b) -> Ordering .) Затем мы можем задать эту функцию упорядочения в sortBy , и он отсортирует ввод в соответствии с этим порядком.

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

Я считаю, что это проще всего бросается в глаза:

sortGT (a1,b1) (a2,b2) = 
  case compare a1 a2 of
    EQ -> compare b1 b2
    LT -> GT
    GT -> LT

Теперь мы используем sortBy, как вы предложили:

*Main> sortBy sortGT [(1, "b"), (1, "a"), (2, "b"), (2, "a")]
[(2,"a"),(2,"b"),(1,"a"),(1,"b")]
10
ответ дан 27 November 2019 в 04:32
поделиться

Всегда сложно составлять функции с двумя аргументами. Вот реализация:

invert :: Ordering -> Ordering
invert GT = LT
invert LT = GT
invert EQ = EQ


sosort :: (Ord a, Ord b) => [(a, b)] -> [(a, b)]
sosort = sortBy (\p p' -> invert $ uncurry compare $ double fst p p') . 
         sortBy (\p p' ->          uncurry compare $ double snd p p')
  where double f a a' = (f a, f a')

Поскольку sortBy ожидает функцию с двумя аргументами, композиция функций не так хороша.

Я протестировал этот код, и он работает на вашем примере.

Как указывает Фред, вы можете написать compare EQ вместо invert . Как указывает Дарио, я мог бы использовать для из Data.Function , но на самом деле для compare == comparing , который я могу использовать вместо этого. Теперь код может быть прочитан только мастером Haskell:

sosort :: (Ord a, Ord b) => [(a, b)] -> [(a, b)]
sosort = sortBy (compare EQ `post` comparing fst) . sortBy (comparing snd)
  where post f g x x' = f (g x x')

Я скомпилировал и запустил этот код, и он работает в исходном примере.

(У меня нет голосов за этот ответ, но благодаря хорошим комментариям я, конечно, много узнал о библиотеке Haskell. Кто знает, какой функции post эквивалентна? Не Hoogle. ..)

Было бы более идиоматичным написать подходящую функцию сравнения для пар , но ваш вопрос касается последовательных сортировок.

0
ответ дан 27 November 2019 в 04:32
поделиться

Могу я предложить следующее?

import Data.List (sortBy)
import Data.Monoid (mconcat)

myPredicate (a1, a2) (b1, b2) = mconcat [compare b1 a1, compare a2 b2]

Вы можете затем выполните сортировку, написав sortBy myPredicate lst . Функция mconcat просто просматривает список и получает первое не- EQ возникновение (или EQ , если все элементы равны EQ и, следовательно, обе пары считаются равными).

Если подумать, составлять список не обязательно.

import Data.List (sortBy)
import Data.Monoid (mappend)

myPredicate (a1, a2) (b1, b2) = compare b1 a1 `mappend` compare a2 b2

Определение mappend для Порядок по существу:

EQ `mappend` x = x
x  `mappend` _ = x

Это именно то, что нам нужно.

Ради удовольствия, обобщив ответ gbacon и сделав его использование более гибким:

import Data.Ord
import Data.List
import Data.Monoid

ascending  = id
descending = flip

sortPairs f x g y = f (comparing x) `mappend` g (comparing y)

mySort = sortBy (sortPairs descending fst ascending snd)
20
ответ дан 27 November 2019 в 04:32
поделиться

Поздравляю с первыми шагами в изучении Haskell. Это великое путешествие!

Риффинг на ответ FredOverflow:

import Data.Ord
import Data.List
import Data.Monoid

main :: IO ()
main = do
  print $ sortBy cmp [(1, "b"), (1, "a"), (2, "b"), (2, "a")]
  where
    cmp = flip (comparing fst) `mappend` comparing snd

Выход:

[(2,"a"),(2,"b"),(1,"a"),(1,"b")]
8
ответ дан 27 November 2019 в 04:32
поделиться
Другие вопросы по тегам:

Похожие вопросы: