映射过滤并减少
标准库中包含的两个最基本的高阶函数是 map
和 filter
。这些函数是通用的,可以在任何可迭代的函数上运行。特别是,它们非常适合在阵列上进行计算。
假设我们有一个学校数据集。每所学校都教授一门特定的科目,有多个类,每班平均学生人数。我们可以使用以下不可变类型为学校建模 :
immutable School
subject::Symbol
nclasses::Int
nstudents::Int # average no. of students per class
end
我们的学校数据集将是一个节目 3:
dataset = [School(:math, 3, 30), School(:math, 5, 20), School(:science, 10, 5)]
假设我们希望找到参加数学课程的学生总人数。为此,我们需要几个步骤:
- 我们必须将数据集缩小到只教数学的学校(
filter
) - 我们必须计算每所学校的学生人数(
map
) - 我们必须将学生人数列表减少到单一值,总和(
reduce
)
一个天真的(不是最有效的)解决方案就是直接使用这三个高阶函数。
function nmath(data)
maths = filter(x -> x.subject === :math, data)
students = map(x -> x.nclasses * x.nstudents, maths)
reduce(+, 0, students)
end
我们在数据集中验证了 190 名数学学生:
julia> nmath(dataset)
190
存在用于组合这些功能并因此改善性能的功能。例如,我们可以使用 mapreduce
函数一步执行映射和缩减,这样可以节省时间和内存。
reduce
仅对+
等关联操作有意义,但偶尔使用非关联操作执行缩减也很有用。提供高阶函数 foldl
和 foldr
以强制执行特定的减少顺序。