简体   繁体   中英

Haskell List Duplicates (if possible with map, elem and foldr)

My Task is to take in Data and "filter" out every duplicate like in the example down below. If possible, I have to use the functions map, elem and foldr I honestly don't know how to do it, if anyone can give me a hint on how to solve the problem, I'd be grateful.

type StudentName = String
type CourseName  = String
type ExamScore   = (CourseName, Float)
type StudentData = [(StudentName, [ExamScore])]

students :: StudentData
students = [
 ("Tim Berners-Lee", [("Maths", 1.3), ("Algorithm", 2.0)]), 
 ("Ada Lovelace",[("Info 1", 3.0), ("Lambda-Maths", 1.7), ("Science", 2.3), ("Data Mining", 2.7)]),
 ("Alan Turing", [("Maths", 1.7), ("operatingSystems", 2.0), ("Lambda-Maths", 1.7)]),
 ("Alonzo Church", [("Info 2", 2.7), ("Systems", 2.3), ("Lambda-Maths", 1.0), ("Algorithm", 3.0)]),
 ("Bjarne Stroustrup", [("Info 1", 2.7), ("Info 2", 1.3), ("operatingSystems", 2.0), ("Topology", 2.3)]),("Bjarne Stroustrup", [("Info 1", 2.7), ("Info 2", 1.3), ("operatingSystems", 2.0), ("Topology", 2.3)]),
 ("Donald E. Knuth", [("Maths", 3.3), ("Info 2", 1.7), ("Lambda-Maths", 2.0), ("Science", 4.0)]),
 ("Grace Hopper", [("Info 3", 1.0), ("operatingSystems", 2.3), ("Systems", 1.7)]),
 ("Annie Easley", [("Maths", 1.0), ("Info 2", 1.7)]),
 ("Edsger W. Dijkstra", [("Topology", 3.3), ("Algorithm", 2.7), ("Systems", 4.0)]),
 ("John von Neumann", [("Maths", 3.3), ("Algoritmische Topologie", 1.0), ("operatingSystems", 1.3), ("Systems", 5.3)])
 ]

courses :: [CourseName]
courses = ["Maths", "Info 1", "Info 2", "Algorithm", "operatingSystems", "Topology", "Lambda-Maths", "Systems", "Science", "Data Mining"]

examResults :: [ExamScore]
examResults = [("Maths", 3.3), ("Topology", 1.0), ("operatingSystems", 1.3), ("Systems", 5.3), ("Info 1", 1.7), ("Info 2", 1.7), ("Data Mining", 0.3)]





filterDuplicates :: StudentData -> StudentData
filterDuplicates



--e.g.
-- filterDuplicates [("Tom", [("Course A", 1.3), ("Course B", 2.0)]), ("Tom", [("Course A", 1.3), ("Course B", 2.0)])]
-- output: [("Tom", [("Course A", 1.3), ("Course B", 2.0)])]

Before you can solve this problem, you need to have a good understanding of the functions elem , map and foldr . (Edit: maybe you won't need filter . I originally read foldr as filter , but there are some useful details in that section that will help so I left it.

elem

If you have some prior programming experience, elem should not be hard. When learning new functions in Haskell, we usually start with the type signature because it can give us a lot of information. For elem it is a -> [a] -> Bool . This means it takes two parameters, a value of type a and a list of values of type a , then it returns a Bool . If the value is in the list than it returns True otherwise it returns False .

> elem 1 [1,2,3]
True
> elem "car" ["boat","bus","airplane"]
False

In a lot of Haskell code you will probably see elem used in infix style by wrapping it in backticks.

> 1 `elem` [1,2,3]
True
> "car" `elem` ["boat","bus","airplane"]
False

filter

Again we will start with the type signature. For filter it is (a -> Bool) -> [a] -> [a] . filter takes two parameters, (a -> Bool) is a function f that takes one parameter of type a and returns a Bool , and [a] is a list of values of type a . It will evaluate function f on each value on the list. When f returns False it will ignore that item, when f returns True , it will collect it and add it to a new list that it returns. Here some examples.

> even [1,2,3,4,5,6]
[2,4,6]
> odd [1,2,3,4,5,6]
[1,3,5]

Before we go any further it will be helpful to understand what lambda functions are (also called anonymous functions). They are a way to define a function without giving a name to the function. It also let's us define a function in line. The syntax looks like this (\\x -> ...) where x is the name of the parameter we pass in and ... should be replaced with a function body. Now let's try to define some lambda functions for filter (remember that they have to return Bool ).

-- keep numbers greater than zero
> filter (\x -> x > 0) [-1,-2,3,5,0,-4,100] 
[3,5,100]
-- keep lists (Strings) longer than 3
> filter (\x -> length x > 3) ["the", "a", "hello", "goodnight", "bye"]
["hello", "goodnight"]

map

Finally map has a type signature that looks like this (a -> b) -> [a] -> [b] . (a -> b) is a function f that takes a value of type a and returns a value of type b , [a] is a list of values of types a , then it returns [b] which is a list of values of type [b] . It evaluates the function f on each value in the list and returns a list with the same number of elements, but the values might be altered. Here are a few examples.

-- here type a is Int and type b is also Int
-- add one to every element in the list
> map (\x -> x + 1) [1,2,3,4]
[2,3,4,5]

-- here type a is String and type b is also String
-- append a "." to every String in the list
> map (\x -> x ++ ".") ["hello", "goodbye"]
["hello.", "goodbye."]

-- here type a is String and type b is Int
> map (\x -> length x) ["hello", "goodbye"]

-- here type a is Int and type b is String
> map (\x -> show x) [1,2,3,4]
["1","2","3","4"]

foldr

foldr is a bit more complicated. Its type signature for a list is (a -> b -> b) -> b -> [a] -> b . After you are comfortable with map , I would take a look at thisStack Overlow question on foldr .

pattern matching

You may also need to understand also understand pattern matching on tuples. Haskell Pattern Matching .

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM