轨道
/
jq
jq
/
练习
/
成绩统计
成绩统计

成绩统计

学习练习

简介

归约

假设我们想对一个数字数组求和。 实现这个目标有很多种方法。

  • 在许多语言中,这个问题会写成一个带累加器变量的循环。

  • 这个问题也可以写成递归函数。 用伪代码写出来,可能像下面这样。

    function Add(X, Sum=0):
      if X is empty then
        return Sum
      else
        return Add(rest(X), Sum + first(X))
      end
    end
    

    这种把问题拆成更小片段的方法,也可以称为“向基本情况归约”。

归约是一种把数据结构的所有元素合并成单个值的做法。 这个过程会遍历数据结构,对每个元素应用一个函数,从而更新累积的结果。

在jq中,这个过程由 reduce过滤器 实现。 在其他语言中,它可能叫“fold”、“fold-left”、“inject”或“aggregate”。

jq的reduce表达式写法如下。

reduce STREAM_EXPRESSION as $var (INITIAL_VALUE; UPDATE_EXPRESSION)
  • STREAM_EXPRESSION是一个由若干项组成的 流,每一项会依次存入$var变量。
  • INITIAL_VALUE是累积结果的起始值(也就是“累加器”)。
  • UPDATE_EXPRESSION会把当前值($var)合并(“折叠”)进累加器。
    • 在这个表达式的上下文里,.表示累加器的值。
    • 表达式的输出会存入累加器,供下一次迭代使用。
    • 最后一次迭代结束后,累积的结果就是reduce的输出。

我们来看一个例子:把数组中的数字加起来。 add过滤器做的就是这件事,不过我们来看看它是怎么实现的。

如果以[10, 20, 30, 40]作为输入,并把 0 作为初始状态,每一步是这样的。

# 状态 元素 归约操作 结果
1 0 10 0 + 10 10
2 10 20 10 + 20 30
3 30 30 30 + 30 60
4 60 40 60 + 40 100

换成jq语法,就是下面这段代码。

0 + 10 | . + 20 | . + 30 | . + 40

我们可以用reduce过滤器来表达它。

[10, 20, 30, 40] | reduce .[] as $n (0; . + $n)     # => 100
Note

add内置函数其实是用reduce实现的,但它以 "null" 作为初始状态(任何数据类型都可以加到 null 上)。

def add: reduce .[] as $x (null; . + $x);

需要注意的几点

  • 在归约表达式里,.就是累加器。 如果输入是一个对象,而你需要在这个归约函数内部引用它,就得把它存到一个变量里。

    {"apple": 10, "banana": 16, "carrot": 4}
    | . as $obj
    | reduce (keys | .[]) as $key (0; . + $obj[$key])     # => 30
    
  • 累加器可以是任意数据类型。 比如你可能想反转一个数组。

    ["A", "B", "C", "D"]
    | reduce .[] as $elem ([]; [$elem] + .)       # => ["D", "C", "B", "A"]
    

说明

你是一名老师。 到了年底,你为每位学生打出了一个数字成绩。 现在你需要把它转换成字母等级,并统计有多少学生拿到了各个字母等级

1. 把数字成绩转换成字母等级

letter_grade函数接收一个数字成绩作为输入,输出对应的字母。 使用以下范围:

字母 成绩
A 90% - 100%
B 80% - 89%
C 70% - 79%
D 60% - 69%
F 0% - 59%

示例:

75 | letter_grade   # => "C"

2. 统计每个字母等级的学生人数

count_letter_grades函数接收一个对象,把学生姓名映射到他们的成绩。 输出是一个对象,把每个字母等级映射到拿到该等级的学生人数。

示例:

{"Joe": 78, "Jane": 93, "Richard": 72} | count_letter_grades
# => {"A": 1, "B": 0, "C": 2, "D": 0, "F": 0}

这道题有几种不同的解法。 为了练习,请使用reduce过滤器。

通过 GitHub 编辑 链接将在新窗口或新标签页中打开
jq Exercism

准备好开始 成绩统计 了吗?

注册 Exercism,借助 12 个概念75 个练习 和真人导师指导,学习并掌握 jq,全部免费。