I am trying to redo the following (simplified) python example in Haskell
zerosList = [0,0,0,0,0,0,0,0,0,0]
for number in range(1,10):
if (number & 1) == 0:
for index in range(number,9,2):
zerosList[index] = zerosList[index] 1
where we change some values in the list from [0,0,0,0,0,0,0,0,0,0]
to [0,0,1,0,2,0,3,0,4,0]
.
I suppose I have to use some filter
s to capture even numbers and then probably use a map
or a foldl
somewhere... but can't figure out how to assemble the whole thing. Something like that?
zeros = take 10 $ cycle [0]
numbers = [1..10]
foldl ( ) zeros $ filter even numbers
or that?
zeros = take 10 $ cycle [0]
numbers = [1..10]
map ( $ filter even numbers) zeros
Well, none of that works so I am clearly on the wrong path. Maybe I should write a replaceAt function?
CodePudding user response:
The most straightforward way to get the output list you want is to observe that it is very predictable: it's just an interleaving of [0..4]
and repeat 0
.
concat $ zipWith (\a b -> [a, b]) [0..4] (repeat 0)
You may object that this isn't implementing your algorithm, it's making use of some insight into your simplification that doesn't exist in your real data. Well, too bad, I would say. Porting an imperative algorithm to a functional language often requires thinking about the problem differently. If my solution is too specialized to work for your real inputs, consider providing more realistic inputs.
CodePudding user response:
You may be overthinking this. When you understand how pattern-matching lists works, this becomes fairly straightforward.
replace :: Int -> [Int] -> [Int]
replace _ [] = []
replace i [x] = [i]
replace i (x:y:xs) = i : y : replace (i 1) xs
We can match an empty list, and that should obviously return an empty list. Since the pattern is every even index being replaced by an increasing number, starting at 0
, we know a list with a single element is just replaced by a list with that increasing int.
Now, we can also pattern match the first two elements of a list, and the tail. We simply replace the first one with the increasing int, don't modify the second, and cons it all onto the result of calling the function on the tail while increasing the int by one.
ghci> replace 0 [0,0,0,0,0,0,0,0,0,0]
[0,0,1,0,2,0,3,0,4,0]
Passing in the initial zero could be easily hidden.
replace :: [Int] -> [Int]
replace = replace' 0
where
replace' _ [] = []
replace' i [x] = [i]
replace' i (x:y:xs) = i : y : replace' (i 1) xs