不使用库函数对列表的一部分进行排序

时间:2019-05-08 20:06:15

标签: haskell

我想对列表的前三个元素进行排序,而其他元素保持不变。而且我不想使用任何库函数,因为我是Haskell的新手。

这是我到目前为止所拥有的:

{-# OPTIONS_GHC -Wincomplete-patterns #-}


sort2 (x, y) = if x > y then (y,x) else (x,y)
sort3 (x,y,z)
    | x > y && y > z = (z,y,x)
    | x > z && z > y = (y,z,x)
    | y > x && x > z = (z,x,y)
    | y > z && z > x = (x,z,y)
    | z > x && x > y = (y,x,z)
    | z > y && y > x = (x,y,z)
    | otherwise = (0,0,0)

--sortfirst3 :: [Int] -> [Int]
sortfirst3 (x:y:z:v:xs) =  sort3(x,y,z) : sortfirst3 (v:xs)

我正在尝试对前三个元素进行排序,将它们放在列表中,然后将其他元素放在另一个列表中,然后将它们彼此串联。但是,由于类型差异元组和列表,这会产生错误。我应该有另一种方法吗?

2 个答案:

答案 0 :(得分:6)

您不需要涉及元组。您可以将为元组编写的内容写为匹配的模式。

sortFirst3 [x, y] = if x > y then [y, x] else [x, y]
sortFirst3 [x, y, z]
    | x >= y && y >= z = [z, y, x]
    | x >= z && z >= y = [y, z, x]
    | y >= x && x >= z = [z, x, y]
    | y >= z && z >= x = [x, z, y]
    | z >= x && x >= y = [y, x, z]
    | z >= y && y >= x = [x, y, z]
sortFirst3 (x : y : z : ws) = sortFirst3 [x, y, z] ++ ws
sortFirst3 xs = xs

最后一行捕获未匹配的内容,即单例和空列表,它们在排序时保持不变。由于元素可能重复出现,因此您在警卫中不应有严格的不平等。还要注意,在您的代码中,即使您没有类型不匹配,对sortFirst3的递归调用也将是错误的,因为对前三个术语进行排序后,其余的前三个将被排序,等等。

答案 1 :(得分:0)

sortfirst3 (x:y:z:v:xs) =  sort3(x,y,z) : sortfirst3 (v:xs)

此定义表示,将列表中的前4个元素从列表中删除,将前3个元素排序为一个元组,然后将其与列表的其余部分一起包含在列表的第四个元素的(递归)结果上。

这揭示了要进行的三个更改。

首先,我们只需要匹配前3个元素,而不是前4个元素,但是我们也应该处理列表<3个元素长的情况。我刚把它弄错了,但是你可以使用例如。改为sort2

sortfirst3 (x:y:z:xs) =  sort3 (x,y,z) : sortfirst3 xs
sortfirst3 _ = error "Can't sort first 3 elements of list shorter than 3 elements"

第二,我们打算对前三个元素进行排序。生成一个3元素列表。 (:) :: a -> [a] -> [a],即。在第一个参数中接受一个元素(而不是列表),我们想要的是连接(++) :: [a] -> [a] -> [a]

sortfirst3 (x:y:z:xs) =  sort3 (x,y,z) ++ sortfirst3 xs

第三,我们打算不影响前三个元素,因此我们实际上不应该对列表的其余部分进行递归调用-否则,我们将列表按3个元素块排序。

sortfirst3 (x:y:z:xs) =  sort3 (x,y,z) ++ xs

现在这几乎是正确的,但是对于sort3来说,如您所标识的那样,它会返回一个元组而不是一个三元素列表。 kuoytfouy的答案对此有所帮助。