user1670032
user1670032

Reputation: 770

Haskell: List Comprehension

I have a function that takes in a list, and if there are 2 identical and successive numbers in the list, and if there is a number, x, elsewhere in the list, that is equivalent, then I want to change x to 0 and return the list.

twoAdjThenThirdZero (x:y:xs) = [if x == y && x `elem` xs then 0 else x | x <- xs]

For some reason, it is omitting the first two elements in the list every time I try to run it.

*Main> twoAdjThenThirdZero [2,3,4,1,2,0,2,3,3]

[4,1,2,0,2,0,0]

Also, the above case is doing the opposite of what I would like. I want to keep the two 3's at the end of the list and make the second element, that 3, to be 0. But it was switched around.

*Main> twoAdjThenThirdZero [2,2,3,1,2,4]

[3,1,0,4]

Does anyone know why this is? Thanks in advance!

Upvotes: 2

Views: 2151

Answers (2)

Johanna Larsson
Johanna Larsson

Reputation: 10761

I see multiple problems here. You start by destructuring the parameter list in the function declaration twoAdjThenThirdZero (x:y:xs). If you want to continue to get x and y for each step, you have to recurse. Instead you switch to using a list comprehension, and a duplicate of x. In the list comprehension you go through xs, which is all elements of the function parameter except the first two (x and y).

If you read the list comprehension out loud I think you can figure it out.

"if x equals y and x is an element of xs then zero else x, for every x in xs". But you want it done for every x in x+y+xs! You are also using the name "x" in two ways, both in your destructuring of the function arguments and as a variable in the list comprehension.

EDIT:

Now I see what you mean. You just have to add that explicit recursion to what you have already.

twoAdjThenThirdZero [] = []
twoAdjThenThirdZero [x] = [x]
twoAdjThenThirdZero (x:y:xs) 
  | x == y && x `elem` xs = x : y : twoAdjThenThirdZero [if z == x then 0 else z | z <- xs]
  | otherwise             = x : twoAdjThenThirdZero (y:xs)

I hope that makes sense to you, if it doesn't, I'll try to explain it further!

EDIT:

phynfo has posted a slightly simpler version of what I was writing!

Upvotes: 1

phynfo
phynfo

Reputation: 4938

Try this:

adjToZero = adjToZero' (allDoubles xs) 

adjToZero' ds [] = []
adjToZero' ds [x] = [x]
adjToZero' ds (x:y:xs) = if (x/=y) && (x `elem` ds) then 0:(adjToZero' ds (y:xs))
                                                    else x:(adjToZero' ds (y:xs))

allDoubles [] = []
allDoubles (x:y:xs) = if (x==y) then x:(allDoubles xs)
                                else allDoubles (y:xs)

Example:

> adjToZero [1,2,1,1]
[0,2,1,1]

Upvotes: 2

Related Questions