[英]Haskell List Duplicates (if possible with map, elem and foldr)
我的任务是接收数据并“过滤”出每个重复项,如下面的示例所示。 如果可能,我必须使用函数 map、elem 和 foldr 我真的不知道该怎么做,如果有人能给我一个如何解决问题的提示,我将不胜感激。
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)])]
在解决这个问题之前,您需要对elem
、 map
和foldr
函数有一个很好的理解。 (编辑:也许你不需要filter
。我最初将foldr
读为filter
,但该部分中有一些有用的细节会有所帮助,所以我离开了。
如果你之前有一些编程经验, elem
应该不难。 在 Haskell 中学习新函数时,我们通常从类型签名开始,因为它可以给我们很多信息。 对于elem
它是a -> [a] -> Bool
。 这意味着它有两个参数,类型的值a
和类型的值的列表a
,那么它返回一个Bool
。 如果该值在列表中,则返回True
否则返回False
。
> elem 1 [1,2,3]
True
> elem "car" ["boat","bus","airplane"]
False
在许多 Haskell 代码中,您可能会看到elem
通过将其包装在反引号中而以中缀样式使用。
> 1 `elem` [1,2,3]
True
> "car" `elem` ["boat","bus","airplane"]
False
我们再次从类型签名开始。 对于filter
它是(a -> Bool) -> [a] -> [a]
。 filter
采用两个参数, (a -> Bool)
是一个函数f
即采用类型的一个参数a
,并返回一个Bool
,并且[a]
是类型的值的列表a
。 它将对列表中的每个值计算函数f
。 当f
返回False
,它将忽略该项目,当f
返回True
,它将收集它并将其添加到它返回的新列表中。 这里有一些例子。
> even [1,2,3,4,5,6]
[2,4,6]
> odd [1,2,3,4,5,6]
[1,3,5]
在我们继续之前,了解什么是 lambda 函数(也称为匿名函数)会很有帮助。 它们是一种定义函数而不给函数命名的方法。 它还让我们在线定义一个函数。 语法看起来像这样(\\x -> ...)
其中x
是我们传入的参数的名称,并且...
应该替换为函数体。 现在让我们尝试为filter
定义一些 lambda 函数(记住它们必须返回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
有一个类型签名,看起来像这样(a -> b) -> [a] -> [b]
。 (a -> b)
是一个函数f
,它接受一个类型a
a 的值并返回一个类型为b
的值, [a]
是一个类型a
的值列表,然后它返回[b]
这是一个值的列表输入[b]
。 它对列表中的每个值计算函数f
并返回一个具有相同元素数量的列表,但这些值可能会改变。 这里有一些例子。
-- 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
有点复杂。 它的列表类型签名是(a -> b -> b) -> b -> [a] -> b
。 在您对map
感到满意后,我会看一下有关 foldr 的 Stack Overlow 问题。
您可能还需要了解元组上的模式匹配。 Haskell 模式匹配。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.