user1351008
user1351008

Reputation: 63

Why doesn't this give the right output?

count :: Eq a => a -> [a] -> Int
count _[]                  = 0
count z (x:xs) | z == x    = 1 + (count z xs)
               | otherwise = count z xs

rmdups :: Eq a => [a] -> [a]
rmdups [] = []
rmdups (x:xs) | count x xs > 0 = rmdups xs
              | otherwise     = x: rmdups xs

The code above compiles but when I input 'ababca' the output of rmdups is 'bca' and I want it to be 'abc'. Why does the a go there? I've been changing the code so much and have no clue why it does this.

Upvotes: 0

Views: 275

Answers (2)

comingstorm
comingstorm

Reputation: 26097

Your rmdups function removes all except the last occurrence of each character.

If you want to remove all except the first occurrence of each character, you could try

reverse . rmdups . reverse

(i.e., reverse before and after using rmdups), or you could rewrite rmdups to keep track of all characters that have previously occurred.

Upvotes: 1

Cat Plus Plus
Cat Plus Plus

Reputation: 129764

Because you remove the duplicates from the front. You could modify rmdups to filter out xs before moving on, so the duplicates are weeded out from the tail:

rmdups :: Eq a => [a] -> [a]
rmdups [] = []
rmdups (x:xs)
    | count x xs > 0 = x : (rmdups $ filter (/= x) xs)
    | otherwise      = x : rmdups xs

In fact, you could even do this without precounting:

rmdups :: Eq a => [a] -> [a]
rmdups []       = []
rmdups (x : xs) = x : filtered
                where filtered = rmdups $ filter (/= x) xs

And of course, in real code, you should rather prefer already-available functions, in this case Data.List.nub.

Upvotes: 10

Related Questions