我需要按照另一个列表的顺序对一个列表进行排序,但我不知道它是如何完成的。
例如:我的列表a
类似于:
[C, B, G, E]
列表b
(设置顺序):
[A, B, C, D, E, F, G, ...]
(例如,这些不是实际值)
然后,列表a
的排序方式应与列表b
相同,因此排序为:
[B, C, E, G]
如何按照另一个列表的顺序进行排序?
答案 0 :(得分:4)
如果我理解,其中一个列表给出了另一个列表中所有元素的相对顺序。即:
> sortWithOrder [5,1,2,3,4] [1,2,3,4,5,5,4,3,2,1]
[5,5,1,1,2,2,3,3,4,4]
这段代码应该有效:
module SortWithOrder where
import qualified Data.Map.Strict as M
import Data.List
import Data.Ord
sortWithOrder :: Ord a
=> [a] -- order list
-> [a] -- source list
-> [a]
sortWithOrder order = sortBy (comparing getOrder)
where
getOrder k = M.findWithDefault (-1) k ordermap
ordermap = M.fromList (zip order [0..])
编辑:更有效的解决方案是使用sortOn
,如下所示:
sortWithOrder order = sortOn getOrder
答案 1 :(得分:3)
您还可以将订单映射到列表并对其进行排序:
Prelude> let order = zip ["A", "B", "C", "D", "E", "F", "G"] [0..]
Prelude> let myList = ["C", "B", "G", "E"]
Prelude> import Data.List (sort)
Prelude> map snd . sort . map (\x -> (lookup x order, x)) $ myList
["B","C","E","G"]
因此我们可以将此函数定义为
sortAlong :: Eq b => [b] -> [b] -> [b]
sortAlong order = map snd . sortBy (comparing fst) . map (\x -> (lookup x z, x))
where
z = zip order [0..]
Ord
约束允许通过Map
提高效率,但此版本只需Eq
:
> sortAlong "ABCDEFG" "CBGE"
"BCEG"