Alex
Alex

Reputation: 667

basic Haskell : searching through multiple lists for the same elements

I've been battling with this problem for a while. I'm trying to create an "organisation" which is a list of Gyms. These gyms are a list of People. Each person has an ID number, an age and an amount of credit.

I want the FindID function to search through the organisation to search through the list of Gyms to find the users with the inputted ID and then return the total of their credit. However, I feel I'm overcomplcating the problem and I am really struggling now.

newtype ID = ID Int deriving (Show)
newtype Age = Age Int deriving (Show)
newtype Credit = Credit Int deriving (Show)
newtype Person = Person (ID, Age, Weight) deriving (Show)   
type Gym = [Person]
type Organisation = [Gym]


getAge :: Person -> Int
getAge (Person(a,Age b,c)) = b

getID :: Person -> Int
getID (Person(ID a,b,c)) = a

getCredit :: Person -> Int
getCredit (Person(a,b,Credit c)) = c

p = Person ( ID 123, Age 65, Credit 12000)
q = Person ( ID 321, Age 64, Credit 0)
e = Person ( ID 453, Age 30, Credit 3000)
r = Person ( ID 123, Age 65, Credit 2310)
s = Person ( ID 364, Age 32, Credit 32340)
t = Person ( ID 123, Age 65, Credit 1300)
org1 = [p,q,e]
org2 = [r,s,t]


hasPerson :: Gym->Int-> Bool
hasPerson gym' id' = not (null(filter hasperson' gym') )
    where 
         hasperson' person' = getID person' == id'

findID:: ID -> Organisation -> Int
findID id' org = total
    where
         IsInGym org' = hasPerson ( org' id' )
         validGym =  filter (IsInGym) org'
         total = sum ( map getCredit validGym)

Upvotes: 1

Views: 304

Answers (1)

bheklilr
bheklilr

Reputation: 54058

First, I would recommend using a record to represent your person, unless you have a particular reason to assign a new type to each field:

type ID = Int
type Age = Int
type Credit = Int
data Person = Person
    { personId :: ID
    , personAge :: Age
    , personCredit :: Credit
    } deriving (Eq, Show)

type Gym = [Person]
type Organization = [Gym]

Next, you can use map to convert a Gym into [Int] with personId, then you can use the built-in elem to check if the ID given appears in that list.

hasPerson :: Gym -> ID -> Bool
hasPerson gym pId = pId `elem` map personId gym

Now, for the findID function, I would suggest renaming it to something like organizationCredit, and I would make a simpler function called gymCredit to calculate it for a single gym:

gymCredit :: ID -> Gym -> Credit
gymCredit pId gym = sum $ map personCredit $ filter (\p -> personId p == pId) gym

organizationCredit :: ID -> Organization -> Credit
organizationCredit pId org = sum $ map (gymCredit pId) org

Alternatively, you could declare your functions as

gymCredit :: Person -> Gym -> Credit
gymCredit person gym = sum $ map personCredit $ filter (\p -> personId p == pId) gym
    where pId = personId person

organizationCredit :: Person -> Organization -> Credit
organizationCredit person org = sum $ map (gymCredit person) org

EDIT: To stick with your old types, you just have to define a few extra functions yourself, then put them in your code where you need to

newtype ID = ID Int deriving (Eq, Show)
newtype Age = Age Int deriving (Eq, Show)
newtype Credit = Credit Int deriving (Eq, Show)
newtype Person = Person (ID, Age, Credit) deriving (Eq, Show)
type Gym = [Person]
type Organisation = [Gym]

personId :: Person -> ID
personId (Person (i, a, c)) = i

personAge :: Person -> Age
personAge (Person (i, a, c)) = a

personCredit :: Person -> Credit
personCredit (Person (i, a, c)) = c

idVal :: ID -> Int
idVal (ID x) = x

ageVal :: Age -> Int
ageVal (Age x) = x

creditVal :: Credit -> Int
creditVal (Credit x) = x

gymCredit :: Person -> Gym -> Credit
gymCredit person gym = Credit $ sum $ map (creditVal . personCredit) $ filter (\p -> personId p == pId) gym
    where pId = personId person

organisationCredit :: Person -> Organisation -> Credit
organisationCredit person org = Credit $ sum $ map (creditVal . gymCredit person) org

It is important to note that I've added Eq to the list of derived typeclasses for each newtype. Without it, you wouldn't be able to directly compare two IDs, you'd have to extract the values first. Another important typeclass to derive is Ord, which lets you use the <, >, <=, and >= operators, as well as a whole bunch of list functions like sort.

Upvotes: 1

Related Questions