Удивительно, если есть лучший способ.
blockquote>В примере, который вы приводите с массивом, я думаю, что все в порядке.
Если Сериализованная строка содержит данные и объекты, которые вы не хотите выполнять без инициализации (например, создание объектов, которые вы действительно не хотите), вы можете использовать сериализованную библиотеку PHP , которая является полным парсером для сериализованных данных.
Он обеспечивает статический доступ к сериализованным данным на низкоуровневом уровне, поэтому вы можете извлекать только подмножество данных и / или манипулировать сериализованными данными без их инициализации. Однако это слишком много для вашего примера, поскольку у вас есть только массив, и вам не нужно фильтровать / отличать слишком много, я думаю.
Вам нужно построить свою функцию 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")]
Сначала мы должны сделать функцию упорядочения, которая принимает две точки и возвращает либо 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")]
Всегда сложно составлять функции с двумя аргументами. Вот реализация:
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. ..)
Было бы более идиоматичным написать подходящую функцию сравнения для пар , но ваш вопрос касается последовательных сортировок.
Могу я предложить следующее?
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)
Поздравляю с первыми шагами в изучении 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")]