将列表排序为元组

use*_*008 0 sorting haskell function

我是Haskell的新手,我正在尝试使用它的第一个元素对元组列表进行排序sort.所以,如果我有,["a", "b", "a", "c", "c"]我会得到类似的东西[(1,"b"), (2,"a"), (2,"c")](在相同数字的情况下按字母顺序排列).

我该怎么做呢?我现在完全迷失了......我仍然试图进入'哈斯克尔的思维方式'.

dav*_*420 9

import Data.List (sort, group)
import Control.Arrow ((&&&))

answer :: Eq a => [a] -> [(Int, a)]
answer = sort . map (length &&& head) . group . sort
Run Code Online (Sandbox Code Playgroud)

但是,由于你是一个初学者,它可能有点多告诉你&&&,所以我会像这样重写它:

import Data.List (sort, group)

answer :: Eq a => [a] -> [(Int, a)]
answer = sort . map f . group . sort
  where f xs @ (x:_) = (length xs, x)
Run Code Online (Sandbox Code Playgroud)

你会注意到我打了sort两次电话.这是故意的.

最后一个sort(左边的那个)对元组的输出列表进行排序,它恰好按元组的第一个元素的升序排序,通过对元组的第二个元素进行排序来打破关系.

初始sort(右边的那个)对输入列表进行排序,因为group它做了什么:它将相邻的相等元素分组到子列表中.(顺便提一下,这些子列表保证永远不会为空 - 否则head在模式匹配中使用或忽略空列表选项是不安全的.)

map f随后打开这些列表(例如["a", "a"])变成了我们所想要的:这些元素出现的次数,以及这些元素的一个代表(例如(2, "a")).


这里的习惯是我们正在使用一个管道:我们的输入进入一个函数,该函数的输出进入另一个函数,依此类推,直到管道末端的函数产生我们作为我们自己的输出呈现的输出.请注意,这只能起作用,因为每个函数只接受一个参数(map接受两个参数,这f是第一个参数,因此map f需要一个参数).

因此,answer即使其参数未明确出现,也是一个函数.这是无风格.

点自由的风格,它看起来像

answer xs = sort . map f . group . sort $ xs
  where f xs @ (x:_) = (length xs, x)
Run Code Online (Sandbox Code Playgroud)

要么

answer xs = sort $ map f $ group $ sort xs
  where f xs @ (x:_) = (length xs, x)
Run Code Online (Sandbox Code Playgroud)

要么

answer xs = sort (map f (group (sort xs)))
  where f xs @ (x:_) = (length xs, x)
Run Code Online (Sandbox Code Playgroud)

在使代码更清晰时使用无点样式是个好主意.

如果您愿意,可以使用<<<运算符(再次来自Control.Arrow,抱歉)使数据流方向更加明确:

import Data.List (sort, group)
import Control.Arrow ((<<<))

answer :: Eq a => [a] -> [(Int, a)]
answer = sort <<< map f <<< group <<< sort
  where f xs @ (x:_) = (length xs, x)
Run Code Online (Sandbox Code Playgroud)

有些人认为这是错误的方式,并希望首先"发生"的功能在左边.这些人可以使用>>>(也来自Control.Arrow),<<<除了它的参数被翻转之外完全相同:

import Data.List (sort, group)
import Control.Arrow ((>>>))

answer :: Eq a => [a] -> [(Int, a)]
answer = sort >>> group >>> map f >>> sort
  where f xs @ (x:_) = (length xs, x)
Run Code Online (Sandbox Code Playgroud)