學習軌道
/
jq
jq
/
練習
/
成績統計
成績統計

成績統計

學習練習

簡介

Reduce

假設我們想把一個數字陣列加總。要達成這個目標有很多種做法。

  • 在許多語言中,這個問題會用一個帶有累加器變數的迴圈來表達。

  • 這個問題也可以寫成遞迴函式。用虛擬碼寫的話,可能會像這樣。

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

    這種把問題拆成更小片段的方法,也可以描述成「朝基本情況縮減」。

Reduce是一種把資料結構中所有元素合併成單一值的方法。這個過程會疊代資料結構,對每個元素套用函式,以更新累加的結果。

在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)合併進累加器(也就是「fold」)。
    • 在這個運算式中,.是累加器的值。
    • 運算式的輸出會存入累加器,供下一次疊代使用。
    • 最後一次疊代結束後,累加的結果就是reduce的輸出。

來看個例子:把陣列裡的數字加總。add篩選器做的正是這件事,不過我們會來看看怎麼實作它。

如果我們用[10, 20, 30, 40]當作輸入,並以零作為初始狀態,每一步會像這樣。

步驟 狀態 元素 縮減函式 結果
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,全部免費。