Home > Blockchain >  Replace multiple elements of a list
Replace multiple elements of a list

Time:11-08

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 filters 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
  • Related