按第二个元素对列表中的列表进行排序

5

当我尝试按第二个元素对列表的列表进行排序时,遇到困难,例如:

list = [[_,B,_,_,_],[_,A,_,_,_],[_,C,_,_,_]]

转化为:

list = [[_,A,_,_,_],[_,B,_,_,_],[_,C,_,_,_]]

我尝试了以下方法:
sortBy compare $ [([1,2]!!1),([2,3]!!1)]

但它过滤掉了第二个元素并将其排序为[2,3]
2个回答

9
你试图对列表[([1,2]!!1),([2,3]!!1)]进行排序,它等同于[2, 3],使用compare进行比较。你想要做的是使用一个函数先获取第二个元素再进行比较,并使用sortBy进行排序:
sortBySecond = sortBy (\ a b -> compare (a !! 1) (b !! 1))

然后将您拥有的列表应用此函数:
sortBySecond [[1, 2], [2, 3]]

您可以通过使用来自 Data.Functionon 使这个函数更加简洁:

import Data.Function

sortBySecond = sortBy (compare `on` (!! 1))

您可以使用Data.Ord中的comparing函数:
sortBySecond = sortBy $ comparing (!! 1)

谢谢你的帮助,伙计。我尝试了你的第二个选项,因为第一个只适用于两个列表,但是当我加载代码时,我遇到了这个错误:无法匹配预期类型 a0 -> a0 -> Ordering' 与实际类型 Ordering' 在调用 compare' 的返回类型中 在 sortBy' 的第一个参数中 即表达式 `(compare on (!! 1))' - seph
首先,我的两个解决方案是相同的 - 在完全相同的情况下都可以工作。其次,在这里很难看到代码格式中的\,所以你是写了 compare \on` (!! 1)还是compare on (!! 1)`? - Tikhon Jelvis
1
在ghci中用 let sortBysecond = ... 绑定它会有问题。单态性限制将使ghci将其默认为 sortBySecond :: [[()]] -> [[()]]。你可以选择:1. 使用签名绑定,let sortBySecond :: Ord a => [[a]] -> [[a]]; sotrBySecond = ...,2. 使用参数绑定,let sortBySecond xs = ...,3. 在提示符上禁用MR,:set -XNoMonomorphismRestriction - Daniel Fischer
2
请注意 comparing foo = compare 'on' foo - Dan Burton
@DanBurton:太酷了,我不知道这个。你可以用反斜杠在内联标记代码中转义反引号:`\\on\\\\`` ==> `on``。 - Tikhon Jelvis
显示剩余4条评论

0
另一个我想到的主意是,通过使用 tail 从列表的第二个元素开始进行排序。我还试图以点无关的方式来编写它 - 这只是给自己的一个练习。
pfsortBySnd :: (Ord a) => [[a]] -> [[a]]
pfsortBySnd = sortBy second
            where second = comparing tail

sortBySnd :: (Ord a) => [[a]] -> [[a]]
sortBySnd xx = sortBy second xx
             where second x y = compare (tail x) (tail y)

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接