DNA 編碼

DNA 編碼

學習練習

簡介

尾呼叫遞迴

當你遞迴走訪可列舉的資料(陣列、位元字串、字串)時,通常會遇到兩個問題:

  • 儲存遞迴函式呼叫軌跡需要多少記憶體
  • 如何有效率地建構出解答

為了處理這些問題,可以使用_累加器_。

累加器是伴隨資料一起傳遞的變數。它用來在每次函式呼叫之間傳遞函式執行當下的狀態,直到抵達_基本情況_。在基本情況中,累加器會用來回傳遞迴函式呼叫的最終值。

累加器應該由函式的作者初始化,而不是由函式的使用者。為了做到這點,請宣告兩個函式:一個公開函式,只接收必要的資料作為引數,並負責初始化累加器;以及一個私有函式,它也接收累加器。在 Elixir 中,常見的慣例是在私有函式的名稱前面加上do_。

# Count the length of a list without an accumulator
def count([]), do: 0
def count([_head | tail]), do: 1 + count(tail)

# Count the length of a list with an accumulator
def count(list), do: do_count(list, 0)

defp do_count([], count), do: count
defp do_count([_head | tail], count), do: do_count(tail, count + 1)

使用累加器讓我們能把遞迴函式轉換成_尾遞迴_函式。如果一個函式最後執行的事情是呼叫自己,它就是尾遞迴。

說明

在你的 DNA 研究實驗室裡,你一直在嘗試各種壓縮研究資料的方法,好節省儲存空間。一位隊友建議把 DNA 資料轉成二進位表示法:

核酸 編碼
空格 0000
A 0001
C 0010
G 0100
T 1000

你思索著這件事:這有可能讓所需的資料儲存成本減半,但代價是犧牲了人類可讀性。於是你決定寫一個模組來編碼與解碼資料,好評估自己究竟省下了多少。

1. 將核酸編碼成二進位值

實作 encode_nucleotide/1,讓它接受核酸的碼點,並回傳編碼後代碼的整數值。

DNA.encode_nucleotide(?A)
# => 1
# (which is equal to 0b0001)

2. 將二進位值解碼回核酸

實作 decode_nucleotide/1,讓它接受編碼後代碼的整數值,並回傳核酸的碼點。

DNA.decode_nucleotide(0b0001)
# => 65
# (which is equal to ?A)

3. 編碼 DNA 字元列表

實作 encode/1,讓它接受代表核酸與空隙的字元列表,並回傳編碼後資料的位元字串。

DNA.encode(~c"AC GT")
# => <<18, 4, 8::size(4)>>

4. 解碼 DNA 位元字串

實作 decode/1,讓它接受代表核酸與空隙的位元字串,並以字元列表回傳解碼後的資料。

DNA.decode(<<132, 2, 1::size(4)>>)
# => ~c"TG CA"
透過 GitHub 編輯 連結會在新視窗或分頁中開啟
Elixir Exercism

準備好開始 DNA 編碼 了嗎?

註冊 Exercism,透過 58 個概念168 個練習 和真人引導來學習並精通 Elixir,全部免費。