AlexJonBarry
AlexJonBarry

Reputation: 55

Remove element from a List and replace it with a new value

So i have a list of ratings for a film, and if a new user rates the film it is added to the list. But if an existing user has already rated it, rating it again will cause the old rating to change to the new one. This is my code so far:

rateFilm :: String -> String -> Int -> [Film] -> [Rating]
rateFilm _ _ _ []                   = []
rateFilm user title number (x:xs)   = if title == name then do
                                        if user == existingUser then do
                                            removeItem (user,number) ratings
                                            ratings ++ [(user,number)]
                                        else do 
                                            ratings ++ [(user,number)]
                                else  do
                                    rateFilm user title number xs
                                where   (name, director, year, ratings) = x
                                        (existingUser,score)            = getUser user ratings

removeItem :: Rating -> [Rating] -> [Rating]
removeItem _ [] = []
removeItem x (y:ys) | x == y    = removeItem x ys
                | otherwise = y : removeItem x ys

And the information for the film is this:

[("Blade Runner","Ridley Scott",1982,[("Amy",6),("Bill",9),("Ian",7),("Kevin",9),("Emma",4),("Sam",5),("Megan",4)]),
 ("The Fly","David Cronenberg",1986,[("Megan",4),("Fred",7),("Chris",5),("Ian",0),("Amy",5)]),
 ("Psycho","Alfred Hitchcock",1960,[("Bill",4),("Jo",4),("Garry",8),("Kevin",7),("Olga",8),("Liz",10),("Ian",9)]),
 ("Body Of Lies","Ridley Scott",2008,[("Sam",3),("Neal",7),("Kevin",2),("Chris",5),("Olga",6)])]

When a new user adds a rating it is fine and the output would be like this:

rateFilm "Alex" "Blade Runner" 8 testDatabase1
[("Amy",6),("Bill",9),("Ian",7),("Kevin",9),("Emma",4),("Sam",5),("Megan",4),("Alex",8)]

However, when an existing user does it, this happens:

rateFilm "Amy" "Blade Runner" 8 testDatabase1
[("Amy",6),("Bill",9),("Ian",7),("Kevin",9),("Emma",4),("Sam",5),("Megan",4),("Amy",8),
("Amy",6),("Bill",9),("Ian",7),("Kevin",9),("Emma",4),("Sam",5),("Megan",4),("Amy",8),
("Amy",6),("Bill",9),("Ian",7),("Kevin",9),("Emma",4),("Sam",5),("Megan",4),("Amy",8),
("Amy",6),("Bill",9),("Ian",7),("Kevin",9),("Emma",4),("Sam",5),("Megan",4),("Amy",8),
("Amy",6),("Bill",9),("Ian",7),("Kevin",9),("Emma",4),("Sam",5),("Megan",4),("Amy",8),
("Amy",6),("Bill",9),("Ian",7),("Kevin",9),("Emma",4),("Sam",5),("Megan",4),("Amy",8),
("Amy",6),("Bill",9),("Ian",7),("Kevin",9),("Emma",4),("Sam",5),("Megan",4),("Amy",8)]

Any ideas as to why, and/or how to fix it? Much appreciated.

Upvotes: 0

Views: 84

Answers (1)

Zeta
Zeta

Reputation: 105955

  1. You really, really don't want to operate on the list monad unless you know what happens in there. The list monad is meant for non-deterministic computations. See the wikibook section or the applicative section of the typeclassopedia.
  2. You want to remove (existingUser, score) not (user, number) from your ratings.

Alltogether we gain the following for rateFilm:

rateFilm user title number (x:xs)   =
    if title == name then
        if user == existingUser then
            removeItem (user,score) ratings ++ [(user,number)]
        else
            ratings ++ [(user,number)]
    else
        rateFilm user title number xs
    where   (name, director, year, ratings)  = x
            (existingUser, score)            = getUser user ratings

Upvotes: 3

Related Questions