#sorting #haskell #types #sql-order-by
#сортировка #haskell #типы #sql-порядок по
Вопрос:
Например, у меня есть следующее,
type something = (Float, Float, Int, Aa, Bb, Cc, Int)
Если бы я захотел найти наименьший something
в базе для их первого элемента (Float), как я мог бы это сделать? Я аргументировал это следующим образом, но мне не удается выяснить, как это реализовать
Поскольку у меня есть список, somethings
самым простым способом должно быть создание моей собственной min
вспомогательной функции, которая сравнивает 2 somethings
и возвращает наименьший из двух. Однако он пытается сделать это «более простым способом», из-за которого я застрял с ошибками компиляции типа…
findMin :: something -> something -> somthing
findMin x y = sortBy (compare `on` fst) x y
Я не знаком с sortBy
и compare on
, я только что наткнулся на аналогичный вопрос здесь, в SO, но мне не удалось заставить его работать. Как новичок в Haskell, есть ли другой способ приблизиться к этому?.
Комментарии:
1. «fst» и «snd» работают только с кортежами с двумя элементами. Для чего-либо более длинного вам, вероятно, лучше использовать «data Something = …», как предлагали другие.
Ответ №1:
Если вы хотите сравнить на основе первого поля типа данных, вы можете позволить Haskell написать код за вас:
data Something = Something Float Float Int String Bool Char Int
deriving (Eq, Ord)
deriving
Предложение указывает, реализации классов типов автоматически генерируются для Something
типа. Здесь мы выводим, Eq
который позволяет нам спросить, равны ли два Something
s (например, с ==
), и Ord
, который позволяет нам сравнить два Something
s и узнать, какой из них «больше».
Поведение Haskell по умолчанию при выводе Ord
заключается в сравнении каждого поля от первого до последнего, поэтому код по умолчанию будет начинаться с сравнения первого Float
из каждого Something
, что является именно тем, что вы хотите.
Как только вы имеете дело с типом, который реализует Ord
, вы можете использовать всевозможные встроенные функции, такие как minimum :: Ord a => [a] -> a
. Это принимает список любого типа, который реализует Ord
, и возвращает наименьший элемент. Итак, в качестве примера:
st1 = Something 3.14 2.72 7 "hello" False 'λ' 42
st2 = Something 3.15 2.72 7 "hello" False 'λ' 42
smallest = minimum [st1,st2]
Ответ №2:
Обычно лучшим вариантом является использование пользовательского data
типа, но если вы действительно хотите использовать кортежи, вы можете начать с определения вспомогательной функции comparingFst
, которая сравнивает на основе первого элемента кортежа.
import Data.Ord
import Data.List
-- Dummy data types for example purposes. Derive from Show just so
-- that the example can be more easily tested interactively in ghci.
data Aa = Aa deriving Show
data Cc = Cc deriving Show
type Something = (Float, Float, Int, Aa, Cc, Int)
comparingFst :: Something -> Something -> Ordering
comparingFst = comparing fstSomething
where fstSomething (x,_,_,_,_,_) = x
Теперь вы можете взять меньший из двух элементов с:
findMin :: Something -> Something -> Something
findMin x y = case comparingFst x y of
LT -> x
_ -> y
или из списка элементов
findMinimum :: [Something] -> Something
findMinimum = minimumBy comparingFst
И вы также можете использовать ту же вспомогательную функцию для сортировки:
sortSomethings :: [Something] -> [Something]
sortSomethings = sortBy comparingFst
Также стоит упомянуть, что кортежи по умолчанию сравниваются поэлементно, начиная с первого элемента, поэтому, предполагая, что ваши типы Aa
и Bb
могут быть производными от Ord
и Eq
, вам не нужно ничего дополнительного, т. Е. пример становится:
import Data.List
data Ab = Ab deriving (Show, Ord, Eq)
data Cc = Cc deriving (Show, Ord, Eq)
type Something = (Float, Float, Int, Ab, Cc, Int)
findMin :: Something -> Something -> Something
findMin x y = min x y
findMinimum :: [Something] -> Something
findMinimum = minimum
sortSomethings :: [Something] -> [Something]
sortSomethings = sort
Другими словами, вы можете просто использовать стандартные min
и sort
функции как есть.
Ответ №3:
Во-первых, у вас есть некоторые синтаксические ошибки.
Вы можете сделать две вещи. Во-первых, следуя модели использования функции доступа для получения нужного поля ( fst
), мы можем определить метки для полей вашего типа:
data Something = Something { field_x, field_y :: Float,
field_z :: Int }
а затем сортировка по field_x
import Data.List
import Data.Function
sortSomethings :: [Something] -> [Something]
sortSomethings = sortBy (compare `on` field_x)
получение минимального значения — это то же самое, что удаление заголовка из отсортированного списка:
minSomethings :: [Something] -> Something
minSomethings = head . sortSomethings
в качестве альтернативы, вы можете написать пользовательский Ord
экземпляр для Something
типа, который сравнивает значения только с помощью field_x
, тогда обычные sort
и minimum
(и другие Ord
функции на основе) будут «просто работать».
Комментарии:
1. Кроме того,
comparing
являетсяcompare on