根据值 (a, b) 的差异对 Int 对列表进行排序
Sort a list of Int pairs by the difference of the values (a, b)
如何根据值 |first - second|
的差值按升序对 list
对 Int
对进行排序?
为了计算差异我写了这段代码:
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
排序函数中?我尝试了几种方法,但总是出现编译错误。
让我们只使用标准库函数!
首先,有一个通用版本的排序函数,名为 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) -> Int
类型的度量函数; 2) 学习如何把它变成一个排序谓词。我告诉过后者是微不足道的,因为它可以通过标准函数 comparing
:
完成
ghci> import Data.Ord
ghci> :t comparing
comparing :: Ord a => (b -> a) -> b -> b -> Ordering
所以我的建议是 comparing ab
是 sortBy
的第一个参数的完美匹配。让我们转向另一个任务:通过标准函数定义 ab
。
考虑 -
函数的类型:
ghci> :t (-)
(-) :: Num a => a -> a -> a
如果用 Int
代替 a
(¹),您几乎可以得到想要的类型,即 Int -> Int -> 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)]
(¹) 您实际上可以要求 GHCi 通过设置名为 TypeApplications
:
的语言扩展来用类型替换函数的类型参数
ghci> :set -XTypeApplications
ghci> :t (-) @Int
(-) @Int :: Int -> Int -> Int
sortBy
虽广为人知,但大多伴随着comparing
。您可以改用 sortOn
。 sortOn
的优点是它使用了 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
我稍后会扩展作业部分以使其成为完整答案。
如何根据值 |first - second|
的差值按升序对 list
对 Int
对进行排序?
为了计算差异我写了这段代码:
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
排序函数中?我尝试了几种方法,但总是出现编译错误。
让我们只使用标准库函数!
首先,有一个通用版本的排序函数,名为 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) -> Int
类型的度量函数; 2) 学习如何把它变成一个排序谓词。我告诉过后者是微不足道的,因为它可以通过标准函数 comparing
:
ghci> import Data.Ord
ghci> :t comparing
comparing :: Ord a => (b -> a) -> b -> b -> Ordering
所以我的建议是 comparing ab
是 sortBy
的第一个参数的完美匹配。让我们转向另一个任务:通过标准函数定义 ab
。
考虑 -
函数的类型:
ghci> :t (-)
(-) :: Num a => a -> a -> a
如果用 Int
代替 a
(¹),您几乎可以得到想要的类型,即 Int -> Int -> 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)]
(¹) 您实际上可以要求 GHCi 通过设置名为 TypeApplications
:
ghci> :set -XTypeApplications
ghci> :t (-) @Int
(-) @Int :: Int -> Int -> Int
sortBy
虽广为人知,但大多伴随着comparing
。您可以改用 sortOn
。 sortOn
的优点是它使用了 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
我稍后会扩展作业部分以使其成为完整答案。