Haskell 99 Questions :: 0x02
archive time: 2024-10-31
继续写写题目......
昨天写了前十题,今天我们继续写 题
题目
Question 11
Modified run-length encoding.
将之前的元组形式的 Run-length 编码改成使用 QCount
的形式
data QCount a = QSingle a | QMultiple Int a
deriving (Show, Eq)
qEncodeModified :: (Eq a) => [a] -> [QCount a]
答案
data QCount a = QSingle a | QMultiple Int a
deriving (Show, Eq)
qEncodeModified :: (Eq a) => [a] -> [QCount a]
qEncodeModified lst =
map qModify (qPack lst)
where
qModify :: (Eq a) => [a] -> QCount a
qModify p = case qLength p of
1 -> QSingle (head p)
len -> QMultiple len (head p)
Question 12
Decode a run-length encoded list.
解码 Run-length 编码
qRunLengthDecode :: [QCount a] -> [a]
答案
qRunLengthDecode :: [QCount a] -> [a]
qRunLengthDecode clst = qReverse (qRunLengthDecodeI clst [])
where
qRunLengthDecodeI :: [QCount a] -> [a] -> [a]
qRunLengthDecodeI [] acc = acc
qRunLengthDecodeI (QSingle e : t) acc = qRunLengthDecodeI t (e : acc)
qRunLengthDecodeI (QMultiple 0 _ : t) acc = qRunLengthDecodeI t acc
qRunLengthDecodeI (QMultiple n e : t) acc = qRunLengthDecodeI (QMultiple (n - 1) e : t) (e : acc)
Question 13
Run-length encoding of a list (direct solution).
直接实现 Run-length 编码,不使用 Question 09 的结果, 实际上就是把 Question 09 的过程修改一下就好
qRunLengthEncodeDirect :: (Eq a) => [a] -> [QCount a]
答案
qRunLengthEncodeDirect :: (Eq a) => [a] -> [QCount a]
qRunLengthEncodeDirect [] = []
qRunLengthEncodeDirect (h : t) = qReverse (qRunLengthEncodeDirectI t (1, h) [])
where
qTupleToCount :: (Int, a) -> QCount a
qTupleToCount (n, e) = case n of
1 -> QSingle e
_ -> QMultiple n e
qRunLengthEncodeDirectI :: (Eq a) => [a] -> (Int, a) -> [QCount a] -> [QCount a]
qRunLengthEncodeDirectI [] p acc = qTupleToCount p : acc
qRunLengthEncodeDirectI (hI : tI) (n, e) acc
| hI == e = qRunLengthEncodeDirectI tI (n + 1, e) acc
| otherwise = qRunLengthEncodeDirectI tI (1, hI) (qTupleToCount (n, e) : acc)
Question 14
Duplicate the elements of a list.
将列表中每个元素都重复一次
qDuplicate :: [a] -> [a]
答案
qDuplicate :: [a] -> [a]
qDuplicate lst = qReverse (qDuplicateI lst [])
where
qDuplicateI :: [a] -> [a] -> [a]
qDuplicateI [] acc = acc
qDuplicateI (h : t) acc = qDuplicateI t (h : h : acc)
Question 15
Replicate the elements of a list a given number of times.
将列表中每个元素都重复 n
次
qReplicate :: [a] -> Int -> [a]
答案
qReplicate :: [a] -> Int -> [a]
qReplicate lst n = qReverse (qReplicateI lst 0 [])
where
qReplicateI :: [a] -> Int -> [a] -> [a]
qReplicateI [] _ acc = acc
qReplicateI (h : t) k acc
| n == k = qReplicateI t 0 acc
| otherwise = qReplicateI (h : t) (k + 1) (h : acc)
Question 16
Drop every N’th element from a list.
将列表中的 每个第 n
个 元素剔除
qDropEveryNth :: [a] -> Int -> [a]
答案
qDropEveryNth :: [a] -> Int -> [a]
qDropEveryNth lst n = qReverse (qDropEveryNthI lst 1 [])
where
qDropEveryNthI :: [a] -> Int -> [a] -> [a]
qDropEveryNthI [] _ acc = acc
qDropEveryNthI (h : t) k acc
| k == n = qDropEveryNthI t 1 acc
| otherwise = qDropEveryNthI t (k + 1) (h : acc)
Question 17
Split a list into two parts; the length of the first part is given.
将列表分割成两个列表,其中第一个列表有 n
个元素
qSplitAt :: [a] -> Int -> ([a], [a])
答案
qSplitAt :: [a] -> Int -> ([a], [a])
qSplitAt lst n = qSplitAtI lst 0 []
where
qSplitAtI :: [a] -> Int -> [a] -> ([a], [a])
qSplitAtI [] _ acc = (acc, [])
qSplitAtI (h : t) k p
| k == n = (qReverse p, h : t)
| otherwise = qSplitAtI t (k + 1) (h : p)
Question 18
Extract a slice from a list.
返回一个列表切片
qSlice :: [a] -> Int -> Int -> [a]
答案
qSlice :: [a] -> Int -> Int -> [a]
qSlice lst start end
| start <= end = qReverse (qSliceI lst 1 [])
| otherwise = []
where
qSliceI :: [a] -> Int -> [a] -> [a]
qSliceI [] _ acc = acc
qSliceI (h : t) k acc
| k < start = qSliceI t (k + 1) acc
| k <= end = qSliceI t (k + 1) (h : acc)
| otherwise = acc
Question 19
Rotate a list N places to the left.
将列表的前 n
个元素和后面元素翻转,负数表示倒数
qRotate :: [a] -> Int -> [a]
答案
qRotate :: [a] -> Int -> [a]
qRotate lst k
| abs k > len = lst
| otherwise = (\(a, b) -> b ++ a) (qSplitAt lst (mod k len))
where
len :: Int
len = qLength lst
Question 20
Remove the K’th element from a list.
删除列表中的第 k
个元素,返回这个元素和修改后的列表
qRemoveAt :: [a] -> Int -> (a, [a])
答案
qRemoveAt :: [a] -> Int -> (Maybe a, [a])
qRemoveAt lst k = qRemoveAtI lst 1 []
where
qRemoveAtI :: [a] -> Int -> [a] -> (Maybe a, [a])
qRemoveAtI [] _ acc = (Nothing, qReverse acc)
qRemoveAtI (h : t) n acc
| n == k = (Just h, qReverse acc ++ t)
| otherwise = qRemoveAtI t (n + 1) (h : acc)
测试用例
这一部分的测试代码如下:
测试代码
module Part02 (part02) where
import Qarks.Nnp
( QCount (..),
qDropEveryNth,
qDuplicate,
qEncodeModified,
qRemoveAt,
qReplicate,
qRotate,
qRunLengthDecode,
qRunLengthEncodeDirect,
qSlice,
qSplitAt,
)
import Test.Hspec
( context,
describe,
it,
shouldBe,
)
import Test.Hspec.Runner (SpecWith)
part02 :: SpecWith ()
part02 = describe "Part02" $ do
context "Qarks.Nnp.qEncodeModified" $ do
it "\"aaaabccaadeeee\"" $ do
qEncodeModified "aaaabccaadeeee"
`shouldBe` [ QMultiple 4 'a',
QSingle 'b',
QMultiple 2 'c',
QMultiple 2 'a',
QSingle 'd',
QMultiple 4 'e'
]
context "Qarks.Nnp.qRunLengthDecode" $ do
it "[ QMultiple 4 'a', QSingle 'b', QMultiple 2 'c', QMultiple 2 'a', QSingle 'd', QMultiple 4 'e']" $ do
qRunLengthDecode
[ QMultiple 4 'a',
QSingle 'b',
QMultiple 2 'c',
QMultiple 2 'a',
QSingle 'd',
QMultiple 4 'e'
]
`shouldBe` "aaaabccaadeeee"
context "Qarks.Nnp.qRunLengthEncodeDirect" $ do
it "\"aaaabccaadeeee\"" $ do
qRunLengthEncodeDirect "aaaabccaadeeee"
`shouldBe` [ QMultiple 4 'a',
QSingle 'b',
QMultiple 2 'c',
QMultiple 2 'a',
QSingle 'd',
QMultiple 4 'e'
]
context "Qarks.Nnp.qDuplicate" $ do
it "[1, 2, 3]" $ do
qDuplicate [1 :: Int, 2, 3] `shouldBe` [1, 1, 2, 2, 3, 3]
context "Qarks.Nnp.qReplicate" $ do
it "\"abc\"" $ do
qReplicate "abc" 3 `shouldBe` "aaabbbccc"
context "Qarks.Nnp.qDropEveryNth" $ do
it "3 of ['a' .. 'k']" $ do
qDropEveryNth ['a' .. 'k'] 3 `shouldBe` "abdeghjk"
context "Qarks.Nnp.qSplitAt" $ do
it "3 of ['a' .. 'k']" $ do
qSplitAt ['a' .. 'k'] 3 `shouldBe` ("abc", "defghijk")
context "Qarks.Nnp.qSlice" $ do
it "['a' .. 'k'] from 3 to 7" $ do
qSlice ['a' .. 'k'] 3 7 `shouldBe` "cdefg"
context "Qarks.Nnp.qRotate" $ do
it "['a' .. 'h'] at 3" $ do
qRotate ['a' .. 'h'] 3 `shouldBe` "defghabc"
it "['a' .. 'h'] at -2" $ do
qRotate ['a' .. 'h'] (-2) `shouldBe` "ghabcdef"
context "Qarks.Nnp.qRemoveAt" $ do
it "['a' .. 'd'] at 2" $ do
qRemoveAt ['a' .. 'd'] 2 `shouldBe` (Just 'b', "acd")