Hamming

Hamming

簡單

簡介

你的身體由帶有 DNA 的細胞組成。 這些細胞會定期耗損,需要汰換,而它們是靠分裂成子細胞來完成這件事。 事實上,人的一生中,身體平均會經歷大約數千兆次的細胞分裂!

細胞分裂時,它們的 DNA 也會複製。 有時在這個過程中會出差錯,使單一片段的 DNA 被編碼成錯誤的資訊。 如果我們比較兩股 DNA 並計算它們之間的差異,就能看出發生了多少錯誤。 這就是所謂的「漢明距離」。

漢明距離不只在生物學,在許多科學領域都很有用,所以這個詞很值得認識一下 :)

說明

計算兩股 DNA 之間的漢明距離。

DNA 是由 C、A、G、T 四個字母所組成。 兩股 DNA 可能長這樣:

GAGCCTACTAACGGGAT
CATCGTAATGACGGCCT
^ ^ ^  ^ ^    ^^

它們之間有 7 處不同,因此漢明距離是 7。

實作說明

漢明距離只定義在長度相同的序列上,所以試圖計算長度不同的兩段序列之間的漢明距離時,應該要失敗。

Option 用來表示一個可能沒有有用結果的運算(例如因為錯誤或無效的輸入)。

如果你不熟悉Option,可以閱讀這篇教學。

Option 是所謂的 Monad,它涵蓋了一種「運算層面」,在這裡指的是值可能不存在。

妥善使用 Monad 可以寫出非常簡潔、優雅又好讀的程式碼。使用不當則很容易得到相反的結果。

想了解更多,可以觀看這段影片。

應該避免的常見陷阱

Option 有幾條經驗法則:

  1. 不需要就不要用。與其寫
def add1(x: Int): Option[Int] = Some(x + 1)

不如寫成

def add1(x: Int): Int = x + 1

(有Option.map可以套用這類簡單的函式,所以不必用Option把它們弄得複雜)。

  1. 如果不是真的需要,就不要「unwrap」。通常都有現成的內建函式可以達到你的目的。過早 unwrap 的跡象是isDefined/isEmpty或模式比對。與其寫
val x: Option[Int] = ...

if (x.isDefined) x.get + 1 else 0
// or
x match {
  case Some(n) => n + 1
  case None => 0
}

不如寫成

x map (_ + 1) getOrElse 0
  1. Monad 可以搭配 for-comprehension 來用,超讚。當你想「組合」多個Option實例時,建議這樣做。與其寫
val xo: Option[Int] = ...
val yo: Option[Int] = ...
val zo: Option[Int] = ...

xo.flatMap(x =>
  yo.flatMap(y =>
    zo.map(z =>
	  x + y + z)))

不如寫成

for {
  x <- xo
  y <- yo
  z <- zo
} yield x + y + z
透過 GitHub 編輯 連結會在新視窗或分頁中開啟
Scala Exercism

準備好開始 Hamming 了嗎?

註冊 Exercism,透過 95 個練習 和真人引導來學習並精通 Scala,全部免費。