在Haskell中自定义排序

时间:2013-05-02 03:22:39

标签: haskell

第二次更新:

我终于遵循了zurgl的建议并编写了something递归遍历和组。感谢所有想要帮助的人!

第一次更新:

我希望它可以是一个排序功能,但不确定,是为了优化随后的分组(最小化组数)。分组收集水平或垂直相邻的元组:

f xs = 
  foldr (\a@(y,x) ((b@(y',x'):xs):bs) -> if (y == y' && abs (x-x') == 1) || 
                                            (x == x' && abs (y-y') == 1)
                                            then (a:b:xs):bs 
                                            else [a]:(b:xs):bs) 
                                            [[last xs]] (init xs)

第二个例子的输出,在“排序”之后:

*Main> f [(0,1),(1,1),(2,1),(2,2),(2,3),(1,3),(0,3),(4,1),(4,2)]
[[(0,1),(1,1),(2,1),(2,2),(2,3),(1,3),(0,3)],[(4,1),(4,2)]]

- 更新结束 -

我在构思排序功能方面遇到困难,希望有人可能知道如何实现它,或者说可能需要比自定义排序更多的东西。我尝试过使用sortBy,但似乎没有取得多大进展。

我如何从中得到:

[(0,1),(0,3),(1,1),(1,3),(2,0),(2,1),(2,3),(4,1),(4,2)]

到此:

[(0,1),(1,1),(2,0),(2,1),(0,3),(1,3),(2,3),(4,1),(4,2)]

两者 y y' x x'之间的0或1的差异应该是主要的。这有意义吗?

第二个例子:

[(0,1),(0,3),(1,1),(1,3),(2,1),(2,2),(2,3),(4,1),(4,2)] 
=>
[(0,1),(1,1),(2,1),(2,2),(2,3),(1,3),(0,3),(4,1),(4,2)]

3 个答案:

答案 0 :(得分:3)

我的Haskell非常生疏但是应该这样做

subsortGT a, b
  | a <= b = GT
  | a > b = LT

sortGT (a1, b1) (a2, b2)
  | a1 + b1 < a2 + b2 = GT
  | a1 + b1 > a2 + b2 = LT
  | a1 + b1 ==  a2 + b2= subsortGT a1 a2

sortBy sortGT [(0,1),(0,3),(1,1),(1,3),(2,0),(2,1),(2,3),(4,1),(4,2)]

答案 1 :(得分:2)

利用元组进行排序

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

customSort = sortBy (comparing (\(x,y) -> (x+y, abs (x-y))))

或箭头指向自由(少点)

import Control.Arrow ((&&&))

customSort = sortBy (comparing $ uncurry ((uncurry (&&&) .) ((+) &&& ((abs .) . subtract))))

答案 2 :(得分:1)

尝试在其上定义自定义数据类型和指定顺序 我建议你这样的事,

data MPair a = MPair a a deriving (Show)

-- some helper to test
toTuple (MPair x y) = (x, y)
fromX x = MPair x x

instance (Eq a) => Eq (MPair a) where
    (MPair a b) == (MPair c d) = (a == c) && (b == d)

-- This is not exactly the ordering you are looking for
-- But at this stage it should no be a pain to define 
-- the required ordering, you just have to implement it below
instance (Ord a) => Ord (MPair a) where
    compare p@(MPair a b) q@(MPair c d)
            | p == q = EQ
            | otherwise = case (compare a c, compare b d) of  
                            (LT, _) -> LT
                            (_, LT) -> LT
                            _       -> GT

-- convert a list of tuple to a list or MPair.  
fromListToMPair :: [(a,a)] -> [MPair a]
fromListToMPair [] = []
fromListToMPair ((a, b):xs) = (MPair a b) : fromListToMPair xs

-- the inverse of the previous one   
fromMPairToList :: [MPair a] -> [(a,a)] 
fromMPairToList [] = []
fromMPairToList ((MPair a b):xs) = (a, b) : fromMPairToList xs

-- A test case
testList = [(0,1),(0,3),(1,1),(1,3),(2,0),(2,1),(2,3),(4,1),(4,2)]

转到ghci并测试它,

>>> fromMPairToList $ sort $ fromListToMPair testList
[(0,1),(0,3),(1,1),(1,3),(2,0),(2,1),(2,3),(4,1),(4,2)]
-- add a test to check the stability of your order.  
>>> fromMPairToList $ sort $ sort $ fromListToMPair testList 
[(0,1),(0,3),(1,1),(1,3),(2,0),(2,1),(2,3),(4,1),(4,2)]
-- ok this is stable

这不符合您的要求,但这是我想说明的另一种方式 事实上,我已经实现了对元组列表进行排序的经典规则 现在我将尝试定义您的“订购”,然后我将重新定义MPair的Ord实例。像这样,

instance (Ord a, Num a) => Ord (MPair a) where  
    compare p@(MPair a b) q@(MPair c d) 
            | p == q        = EQ 
            | check a b c d = LT  
            | otherwise     = GT 
                where 
                  pred x y = (abs (x - y)) < 2
                  check a b c d = pred a c && pred b d

然后当我将测试重做为ghci时,

>>> fromMPairToList $ sort $ fromListToMPair testList
[(4,1),(4,2),(2,3),(2,0),(2,1),(1,3),(1,1),(0,3),(0,1)]
>>> fromMPairToList $ sort $ sort $ fromListToMPair testList
[(0,1),(0,3),(2,0),(1,1),(2,3),(1,3),(2,1),(4,1),(4,2)]
-- no this won't work, this is not an ordering, you cannot sort.  

我意识到订单的稳定性不满足,然后排序不是您需要的。

最后,我想说这没有意义,因为你的标准没有在你的元组列表上定义一个顺序。您的标准是判别式,它将允许您创建两个子组数据。 ([标准x为真],[标准x不为真])。像往常一样对元组列表进行排序,并定义一个指定函数(基于您的标准),这将创建两个不同的组。

PS:也许您可以使用基于您的标准的函数为您的数据建立订单,但我不知道如何实现它。