在Haskell中,如何使用内置的sortBy函数对对象列表(元组)进行排序?

ecl*_*oob 37 sorting haskell tuples

我是Haskell的初学者所以请耐心等待.(刚开始学习昨天!)我如何主要按照第一个组件(从最高到最小)排序元组列表,然后按第二个组件(从最小到最高)排序?输入/输出的示例如下:

[(1, "b"), (1, "a"), (2, "b"), (2, "a")] (输入)

[(1, "a"), (2, "a"), (1, "b"), (2, "b")] (中间步骤)

[(2, "a"), (2, "b"), (1, "a"), (1, "b")] (输出)

我尝试使用以下但它输出错误:

sortGT a b = GT

sortBy sortGT lst
Run Code Online (Sandbox Code Playgroud)

我确信我只能使用sortBy,但我无法弄明白.任何帮助将非常感谢!

3le*_*gos 38

您需要构建您的函数sortGT,以便按您希望的方式比较对:

sortGT (a1, b1) (a2, b2)
  | a1 < a2 = GT
  | a1 > a2 = LT
  | a1 == a2 = compare b1 b2
Run Code Online (Sandbox Code Playgroud)


使用这个你得到以下结果(我使用ghci):

*Main Data.List> sortBy sortGT [(1, "b"), (1, "a"), (2, "b"), (2, "a")]
[(2,"a"),(2,"b"),(1,"a"),(1,"b")]
Run Code Online (Sandbox Code Playgroud)

  • `sortGT`的更快定义是`(翻译比较\`on \`fst)<> compare`.由于函数的Monoid定义很好.或者`(翻译比较\`on \`fst)<>(比较\`on \`snd)`以获得更快的速度,因为每个元组的第一个元素只进行一次比较. (3认同)

fre*_*low 20

我可以建议如下吗?

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

myPredicate (a1, a2) (b1, b2) = mconcat [compare b1 a1, compare a2 b2]
Run Code Online (Sandbox Code Playgroud)

然后你可以通过写作进行排序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
Run Code Online (Sandbox Code Playgroud)

mappendfor 的定义Ordering基本上是:

EQ `mappend` x = x
x  `mappend` _ = x
Run Code Online (Sandbox Code Playgroud)

这正是我们所需要的.

只是为了好玩,概括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)
Run Code Online (Sandbox Code Playgroud)


Has*_*ant 10

首先,我们应该使排序函数接受两次操作并返回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
Run Code Online (Sandbox Code Playgroud)

现在我们按照您的建议使用sortBy:

*Main> sortBy sortGT [(1, "b"), (1, "a"), (2, "b"), (2, "a")]
[(2,"a"),(2,"b"),(1,"a"),(1,"b")]
Run Code Online (Sandbox Code Playgroud)


Gre*_*con 8

恭喜您迈出了学习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
Run Code Online (Sandbox Code Playgroud)

输出:

[(2,"a"),(2,"b"),(1,"a"),(1,"b")]