【问题标题】:Sort a list of Int pairs by the difference of the values (a, b)按值 (a, b) 的差异对 Int 对列表进行排序
【发布时间】:2018-05-28 06:34:28
【问题描述】:

如何按|first - second| 值的差异按升序对Int 对中的list 进行排序?

为了计算差异我写了这段代码:

ab :: (Int, Int) -> Int
ab (x, y) = if x - y >= 0 then (x - y)
            else (x - y) * (-1)

我想在我得到的值上使用quicksort

sort :: [(Int,Int)] -> [(Int,Int)]
sort [] = []
sort (x:xs) = sort smallerOrEqual ++ [x] ++ sort larger
          where smallerOrEqual = [a | a <- xs, a <= x]
                larger = [a | a <- xs, a > x]

问题是如何将我的ab 函数构建到the 排序函数中?我尝试了几种方法,但总是出现编译器错误。

【问题讨论】:

  • smallerOrEqual 是什么?它有什么类型?你能用ab写一个适合那种类型的函数吗?
  • smallerOrEqual 具有与sort 函数相同的类型:[(Int, Int)] -&gt; [(Int, Int)]。我不知道如何编写ab 以使其适合我的sort 函数。因为虽然ab 用于配对,但我在sort 中使用配对列表。我是haskell的新手,这让我很困惑:(
  • smallerOrEqual 的定义在sort 函数中。见where 声明:where smallerOrEqual = [a | a &lt;- xs, a &lt;= x]
  • 您尝试过什么,尝试出现了什么错误?
  • 对不起,我的扳机有点快,那里:$

标签: haskell tuples list-comprehension quicksort


【解决方案1】:

让我们只使用标准库函数!

首先,有一个通用版本的排序函数,名为sortBy(我将展示相关函数的类型,使用 GHCi 出色的 :t 命令):

ghci> import Data.List
ghci> :t sortBy
sortBy :: (a -> a -> Ordering) -> [a] -> [a]

sortBy 的第一个参数表明,要比较元素,我们需要一个排序谓词——该函数接受列表中的两个元素并判断第一个元素是否更大。在许多情况下,包括您在内,您不必自己定义这样的函数。相反,您可以使用“衡量”列表元素的重要性的函数。例如。你有一个列表元素(x,y),它的度量是|x-y|——这正是你的ab函数,但请记住,我们希望它通过标准函数来定义。

现在,我们有两个任务:1)定义(Int, Int) -&gt; Int类型的测量函数; 2)学习如何把它变成一个排序谓词。我告诉过后者是微不足道的,因为它可以通过标准函数comparing

ghci> import Data.Ord
ghci> :t comparing
comparing :: Ord a => (b -> a) -> b -> b -> Ordering

所以我的建议是comparing absortBy 的第一个参数完美匹配。不让我们转向另一个任务:通过标准函数定义ab

考虑-函数的类型:

ghci> :t (-)
(-) :: Num a => a -> a -> a

如果您将Int 替换为a(¹),您将获得几乎您想要的类型,即Int -&gt; Int -&gt; Int。在这里,我们遇到了非常频繁的任务,即将一个函数从两个参数 ((-)) 转换为一个作用于对的函数。幸运的是,有一个标准函数可以做到这一点,即uncurry

ghci> :t uncurry (-)
uncurry (-) :: Num c => (c, c) -> c

这就是我们需要的!现在我们只需要使用计算|·|abs 函数来管道它,我们很好。我们通过. 编写函数。得到的解决方案是这个:

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

sortAbsPairs :: [(Int,Int)] -> [(Int,Int)]
sortAbsPairs = sortBy (comparing $ abs . uncurry (-))

假设你将它保存在sort.hs 中,你可以在 GHCi 中试用它:

ghci>:l sort.hs
Ok, one module loaded.
ghci> sortAbsPairs [(8,20), (5, 10), (1,2)]
    [(1, 2), (5, 10), (8, 20)]

(¹) 您实际上可以通过设置一个名为 TypeApplications 的语言扩展来让 GHCi 用类型替换函数的类型参数:

ghci> :set -XTypeApplications
ghci> :t (-) @Int
(-) @Int :: Int -> Int -> Int

【讨论】:

    【解决方案2】:

    虽然sortBy 是众所周知的,但它大多伴随着comparing。您可以改用sortOnsortOn 的优点是它使用 Schwartzian 变换,即它只为每个元素计算一次差异。

    --Prelude Data.List> :t sortOn
    --sortOn :: Ord b => (a -> b) -> [a] -> [a]
    
    import Data.List(sortOn)
    sort = sortOn (abs . uncurry (-))
    

    但如果你真的想使用你原来的排序,模式匹配对:

    sort ((x,x'):xs) = [ (a,a') | (a,a') <- xs, -- ... your homework here
    

    我稍后会扩展家庭作业部分以使其成为完整的答案。

    【讨论】:

      猜你喜欢
      • 2015-03-05
      • 1970-01-01
      • 2017-10-03
      • 1970-01-01
      • 2022-11-17
      • 1970-01-01
      • 2022-01-18
      • 2022-01-14
      • 2021-01-25
      相关资源
      最近更新 更多