【问题标题】:Custom Sort in HaskellHaskell 中的自定义排序
【发布时间】:2013-05-02 03:22:38
【问题描述】:

第二次更新:

我终于按照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)]

both 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)]

【问题讨论】:

  • 我不明白您所说的“y y' 和 x x' 之间的 0 或 1 的差异应该是主要的。”
  • 是的,我也不明白。你能解释一下为什么应该例如(2,1) 在 (0,3) 之前?
  • 不确定您描述的内容是否可以表示为排序,因为您不是简单地比较(2,1)(0,3),而是在另一个值(2,0) 的上下文中进行比较。例如,给定[(0,0),(0,1),(0,2)],那和[(0, 2), (0, 1), (0, 0)] 都是有效的。如果我误解了您的描述,请详细说明。
  • 我已经投票结束:groovy 的两个(或三个,看看 Charles D 的回答)示例并不能解释他想要什么,并且试图猜测可能的配对顺序是在浪费每个人的时间.
  • 你的意图很不明确。我可以推荐一个策略。首先,定义一个从对到表示排序的结果类型的转换函数,例如算术运算的数值结果。其次,将此函数与sortWith 一起使用对您的数据进行排序。

标签: haskell


【解决方案1】:

我的 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)]

【讨论】:

  • 我收到了这个[(4,2),(4,1),(2,3),(1,3),(2,1),(0,3),(2,0),(1,1),(0,1)] 我做错了什么吗?
  • 我想我只是倒着写了尝试在 subsortGT 中交换 LT 和 GT?我现在正在安装 GHC,哈哈。
  • 好的...[(4,2),(2,3),(4,1),(1,3),(0,3),(2,1),(1,1),(2,0),(0,1)]
  • 我以为我认出了你的名字,哈哈......我这样做的原因是为了回答你所做的同样的问题:stackoverflow.com/questions/16326318/finding-blocks-in-arrays/… 我的想法是只列出 1 的坐标,然后排序(正如我正在尝试做的那样),然后简单地将它们按相同的主体 (diff x-x' and y-y' less than 2) 分组以获取对象的数量!
  • ohh k,现在我知道你想要做什么,这不是一个排序操作。我会看看我是否想不通,我很开心。
【解决方案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))))

【讨论】:

  • 感谢您的考虑——它确实适用于我发布的示例,但对于这个[(0,1),(0,3),(1,1),(1,3),(2,1),(2,2),(2,3),(4,1),(4,2)],它输出[(0,1),(1,1),(2,1),(0,3),(2,2),(1,3),(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】:

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

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:也许您可以使用基于您的标准的函数在您的数据上建立订单,但我不知道如何实现它。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2016-05-07
    • 1970-01-01
    • 2011-06-06
    • 2014-06-30
    • 2010-10-27
    • 2013-04-09
    • 2019-12-06
    相关资源
    最近更新 更多