patternMinor
Double every 2nd item in a list
Viewed 0 times
itemeverydoublelist2nd
Problem
Some exercise required me to write a piece of code to double every second item in a list. My first thought was just using cons and I came up with the following:
While it's straightforward and does work, it just doesn't look that elegant and I'm curious how this could be rewritten in a more elegant fashion :)
doubleSecond :: Num a => [a] -> [a]
doubleSecond [] = []
doubleSecond [x] = [x]
doubleSecond (x:y:xs) = x : (y * 2) : doubleSecond xsWhile it's straightforward and does work, it just doesn't look that elegant and I'm curious how this could be rewritten in a more elegant fashion :)
Solution
Built-ins and generality
It is a good first try, but I discourage explicit recursion and suggest a larger use of built-ins, Haskell provides you with incredibly powerful and general functions. Also writing something a bit more general will make you familiar with first class functions (the core of the Haskell experience).
Decomposition
As always, I am going to divide the task in smaller, more manageable parts:
Given a function and a list, apply the function to each second item of the list.
This function is quite advanced, let me explain it:
The second argument is omitted, as it can be 'currried' (simplified) away.
The
It is a good first try, but I discourage explicit recursion and suggest a larger use of built-ins, Haskell provides you with incredibly powerful and general functions. Also writing something a bit more general will make you familiar with first class functions (the core of the Haskell experience).
Decomposition
As always, I am going to divide the task in smaller, more manageable parts:
- Find out how to apply a function to each second item of list.
- Give
multiply_by_twoas argument to the function above.
mapSecondmapSecond :: (a -> a) -> [a] -> [a]
mapSecond f = zipWith ($) (cycle [id, f])Given a function and a list, apply the function to each second item of the list.
This function is quite advanced, let me explain it:
zipWith: given a function and two list applies the function to each pair. If you are familiar with Python,zip = zipWith (,)
Prelude> zipWith (++) ["Hello", "Foo"] ["World", "Bar"]
["HelloWorld","FooBar"]$: given a function and two arguments, applies it to the arguments.
Prelude> ($) (*) 2 5
10cycle: given a list repeats it forever.
Prelude> take 10 $ cycle [1,2,3]
[1,2,3,1,2,3,1,2,3,1]The second argument is omitted, as it can be 'currried' (simplified) away.
The
main function is now:main = print $ ( mapSecond (* 2) ) [1,2,3,4,5,6]Code Snippets
mapSecond :: (a -> a) -> [a] -> [a]
mapSecond f = zipWith ($) (cycle [id, f])Prelude> zipWith (++) ["Hello", "Foo"] ["World", "Bar"]
["HelloWorld","FooBar"]Prelude> ($) (*) 2 5
10Prelude> take 10 $ cycle [1,2,3]
[1,2,3,1,2,3,1,2,3,1]main = print $ ( mapSecond (* 2) ) [1,2,3,4,5,6]Context
StackExchange Code Review Q#110830, answer score: 4
Revisions (0)
No revisions yet.