其他人能在Haskell中这样编码吗:数字翻倍数字需要加倍,为此可以定义以下功能:
doubleDigits :: [Integer] -> [Integer]
函数doubleDigits
必须从右边开始每隔一个数字加倍。倒数第二个数字先加倍,然后倒数第四个。。。,等等
Input: doubleDigits [1,2,3,4,5,6,7]
Output: [1,4,3,8,5,12,7]
toDigitsReverse :: Integer -> [Integer]
toDigitsReverse n = reverse (toDigits n)
-- function to help double every other element of list
doubleDigitsHelper :: [Integer] -> Integer -> [Integer]
doubleDigitsHelper l t
| l == [] = []
| t == 0 = [head l] ++ (doubleDigitsHelper (drop 1 l) 1)
| t == 1 = [2*(head l)] ++ (doubleDigitsHelper (drop 1 l) 0)
-- function to double every other element
doubleDigits :: [Integer] -> [Integer]
doubleDigits l = reverse (doubleDigitsHelper (reverse l) 0)
另一种方法:
让我们zip
列表中的元素及其索引。
[1,2,3,4,5,6,7] `zip` [0..]
我们得到:
[(1,0),(2,1),(3,2),(4,3),(5,4),(6,5),(7,6)]
然后我们可以map
这个到想要的结果:
let f (x, i) = if even i then x else x * 2 in map f $ [1,2,3,4,5,6,7] `zip` [0..]
结果是:
[1,4,3,8,5,12,7]
或者写得有点不同:
doubleDigits lst = map f lst'
where
lst' = lst `zip` [0..]
f (x, i)
| even i = x
| otherwise = x * 2
因为您想从右侧开始将其他元素加倍,所以您可以简单地反转列表,用索引压缩它,映射,然后保留输出。
doubleDigits lst = reverse $ map f lst'
where
lst' = (reverse lst) `zip` [0..]
f (x, i)
| even i = x
| otherwise = x * 2
我想说的是,首先reverse
列表没有意义,确定累加器(t
)是偶数还是奇数(有内置的函数用于此,例如even
),然后采取相应的行动。接下来可以改进代码的是使用模式匹配,而不是==
和head
/tail
调用。此外,我还更改了助手函数的顺序:
-- function to help double every other element of list
doubleDigitsHelper :: Integer -> [Integer] -> [Integer]
doubleDigitsHelper _ [] = []
doubleDigitsHelper t (x:xs) | even t = x : doubleDigitsHelper (t+1) xs
| otherwise = 2*x : doubleDigitsHelper (t+1) xs
-- function to double every other element
doubleDigits :: [Integer] -> [Integer]
doubleDigits = doubleDigitsHelper 0
您可以将要应用的交替函数放在列表(cycle [id, (*2)]
)中,并使用zipWith
将这些函数应用于您的列表。
doubleDigits :: Num a => [a] -> [a]
doubleDigits = reverse . zipWith ($) (cycle [id, (*2)]) . reverse
如果你想从右边开始交替,我看不出有什么优雅的方法可以扭转列表。例如,您可以先查看列表的长度,然后在此基础上更改函数的顺序,但这会使函数稍微复杂一些。
doubleDigits xs = zipWith ($) fs xs
where fs = (if even . length $ xs then tail else id) $ cycle [id, (*2)]