Can someone else this codes in Haskell: Doubling Digits The digits need to be doubled, for this the following function can be defined:
doubleDigits :: [Integer] -> [Integer]
The function doubleDigits
must double every other number starting from the right.
The second-to-last number is doubled first, then the fourth-to-last, ..., and so on.
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)
CodePudding user response:
An alternate approach:
Let's zip
the elements of the list with their indices.
[1,2,3,4,5,6,7] `zip` [0..]
We get:
[(1,0),(2,1),(3,2),(4,3),(5,4),(6,5),(7,6)]
Then we can map
this to the desired result:
let f (x, i) = if even i then x else x * 2 in map f $ [1,2,3,4,5,6,7] `zip` [0..]
And the result is:
[1,4,3,8,5,12,7]
Or written a little bit differently:
doubleDigits lst = map f lst'
where
lst' = lst `zip` [0..]
f (x, i)
| even i = x
| otherwise = x * 2
Because you want to double every other element starting from the right, you can simply reverse the list, zip it with indices, map, then reserve the output.
doubleDigits lst = reverse $ map f lst'
where
lst' = (reverse lst) `zip` [0..]
f (x, i)
| even i = x
| otherwise = x * 2
CodePudding user response:
I would say that first of all there is no point to reverse
list, determine if accumulator (t
) is even or odd (there are build in functions for that - for example even
) and then act accordingly. Next what can imporve the code - use pattern matching instead of ==
and head
/tail
calls. Also I've changed the order of the helper function:
-- 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
CodePudding user response:
You could put the alternating functions you want to apply in a list (cycle [id, (*2)]
) and apply these to your list using zipWith
.
doubleDigits :: Num a => [a] -> [a]
doubleDigits = reverse . zipWith ($) (cycle [id, (*2)]) . reverse
I don't see an elegant way around reversing the list if you want to alternate starting from the right. You could, for example, look at the length of the list first and change the order of the functions based on that, but that would complicate the function a little.
doubleDigits xs = zipWith ($) fs xs
where fs = (if even . length $ xs then tail else id) $ cycle [id, (*2)]