假设函数的输入是:
[(6,-275),(3,123),(7,1000),(9,-572),(3,333),(1,-23)]
输出应为:
[(9,-572),(6,-275),(1,-23),(3,123),(3,333),(7,1000)]
这是我想要的功能:
sortBySnd :: Ord a => [(a,a)] -> [(a,a)]
sortBySnd [] = []
sortBySnd [(_,a),(_,b)]
| a < b = [(_,a),(_,b)]
| a > b = [(_,b),(_,a)]
| a == b = [(_,a),(_,b)]
这当然是非常错误的,但我只想展示我想要实现的目标。
对于排序函数,可以使用mergesort或除sortBy之外的一些内置排序函数。
答案 0 :(得分:5)
这就是我的意思:
import Data.List (sort)
import Data.Tuple (swap)
sortT = map swap . sort . map swap
答案 1 :(得分:2)
只是为了好玩,使用Data.Map
:
uncurry (fmap.flip(,)) -- distribute the keys over the values
<=< toList -- convert back to a list, now sorted
. fromListWith (++) -- convert to Map, collect values with same keys
. fmap (fmap(:[]).swap) -- swap the pairs and promote snd to a list
答案 2 :(得分:1)
正如Carsten所做的那样,你可以通过“屏蔽”第一个元素然后只使用正常排序来实现这一点。翻转元素实现了这一点,虽然它相当糟糕(第一个元素仍然会被排序,只有较低的优先级)...一个更好的方法是使用一个真正比较的类型第二个要素:
data SndOrd a b = SndOrd a b
instance Eq SndOrd where SndOrd _ x == SndOrd _ y = x==y
instance Ord SndOrd where compare (SndOrd _ x) (SndOrd _ y) = compare x y
然后你可以做
sortT = map (\(SndOrd a b) -> (a,b)) . sort . map (\(a,b) -> SndOrd a b)
但是,我不建议这样做,因为通常期望==
是恰当的平等,但是使用这种方法你有SndOrd 1 2 == SndOrd 3 2
。
当然,正确的方法是使用 sortBy
!或者自己实施。编写一般的排序算法是一个可以在互联网上找到吨资源的主题,你应该在询问StackOverflow之前先查看一下...
你自己的尝试并非毫无意义。首先,我们需要通过递归来实际覆盖除0或2以外的长度列表:
sortBySnd' ((_,a):(_,b):l)
| a < b = (_,a) : sortBySnd' ((_,b):l)
| a > b = (_,b) : sortBySnd' ((_,a):l)
| a == b = (_,a) : sortBySnd' ((_,b):l)
sortBySnd' l = l -- lists with length <2 are already sorted!
请注意,您可以统一第一和第三名警卫:
sortBySnd' ((_,a):(_,b):l)
| a > b = (_,b) : sortBySnd' ((_,a):l)
| otherwise = (_,a) : sortBySnd' ((_,b):l)
sortBySnd' l = l -- lists with length <2 are already sorted!
现在,这还不行,因为每个元素最多可以在列表中向后移动一个单元格。你可以通过迭代整个过程来挽救这个,就像列表中有元素一样:
sortBySnd'' l = iterate sortBySnd' l !! length l
这是bubble sort,这是一种非常低效的算法,但它可以工作。