映射过滤并减少

标准库中包含的两个最基本的高阶函数是 mapfilter。这些函数是通用的,可以在任何可迭代的函数上运行。特别是,它们非常适合在阵列上进行计算。

假设我们有一个学校数据集。每所学校都教授一门特定的科目,有多个类,每班平均学生人数。我们可以使用以下不可变类型为学校建模 :

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 仅对+关联操作有意义,但偶尔使用非关联操作执行缩减也很有用。提供高阶函数 foldlfoldr 以强制执行特定的减少顺序。