根据模板排序列表

时间:2015-08-06 18:28:36

标签: sorting haskell

如何根据另一个列表(模板)对Haskell中的列表进行排序(重新定位其元素)?例如,我有2个列表:

[1,2,3]
[(2,'b'),(1,'a'),(3,'c')]

我想对第二个列表进行排序,以便每个元素的第一个对应于第一个列表的元素。即我希望它是[(1,'a'),(2,'b'),(3,'c')]

我写了一个非常不优雅的实现:

sortMimicking :: (Eq a) => [a] -> [(a, b)] -> [(a, b)]
sortMimicking template xs = filterJust $ r (reverse template) xs []
  where filterJust [] = []
        filterJust (x:xs) = case x of
          Nothing -> filterJust xs
          Just element -> element:filterJust xs
        deleteWith comparison xs = [ x | x <- xs, not $ comparison x ]
        r _ [] acc = acc
        r (t:ts) xs acc = r ts
                          (deleteWith ((==t) . fst) xs)
                          (find ((==t) . fst) xs : acc)

它只适用于对的列表,所以我写了这个概括:

sortMimickingBy :: (Eq a) => (b -> a) -> [a] -> [b] -> [b]
sortMimickingBy c template xs = filterJust $ r (reverse template) xs []
  where filterJust [] = []
        filterJust (x:xs) = case x of
          Nothing -> filterJust xs
          Just element -> element:filterJust xs
        deleteWith comparison xs = [ x | x <- xs, not $ comparison x ]
        r _ [] acc = acc
        r (t:ts) xs acc = r ts
                          (deleteWith ((==t) . c) xs)
                          (find ((==t) . c) xs : acc)

我尝试使用sortWith模块中的GHC.Exts来提出更优雅的功能,但无济于事。有a similar Python question

2 个答案:

答案 0 :(得分:2)

如果您允许Ord a,则可以使用线性元素查找执行O(n log n)解决方案而不是二次解决方案。我们的想法是记住模板列表元素的原始位置(通过压缩[0..]),然后排序多次以对齐元素,然后恢复正确的顺序。

import Data.List
import Data.Ord

sortMimicking :: Ord a => [a] -> [(a, b)] -> [(a, b)]
sortMimicking guide xs = map snd $ sortBy (comparing (snd . fst)) $ zip guide' xs'
  where
    guide' = sortBy (comparing fst) $ zip guide [0..]
    xs'    = sortBy (comparing fst) xs

答案 1 :(得分:0)

试试这个:

import Data.List (sortBy, elemIndex)
import Data.Ord (comparing)

mySort :: [Int] -> [(Int,a)] -> [(Int,a)]
mySort as bs = sortBy (comparing go) bs
  where go (a,b) = maybe 0 id (elemIndex a as)

示例:

ghci> mySort [3,2,1] [(1,'a'), (2,'b'), (3,'c')]
[(3,'c'),(2,'b'),(1,'a')]

基本上go (a,b)通过比较每对中的a来计算第一个列表中的sortBy (comparing go) ...索引和go排序。

注意:由于elemIndex每次调用时都会从列表前面扫描,因此效率不高。