汉明

汉明

简单

简介

你的身体由含有 DNA 的细胞组成。 这些细胞会定期损耗,需要更替,而它们靠分裂成子细胞来完成这件事。 事实上,普通人的身体一生中会经历大约 1 亿亿次细胞分裂!

细胞分裂时,它们的 DNA 也会复制。 有时在这个过程中会出差错,单个 DNA 片段会被编码成错误的信息。 如果我们比较两条 DNA 链并数出它们之间的差异,就能看出发生了多少错误。 这就是所谓的“汉明距离”。

汉明距离不只在生物学中有用,在许多科学领域都很有用,所以这是个值得熟悉的好说法 :)

说明

计算两条 DNA 链之间的汉明距离。

我们使用字母 C、A、G 和 T 来表示 DNA。 两条链可能看起来像这样:

GAGCCTACTAACGGGAT
CATCGTAATGACGGCCT
^ ^ ^  ^ ^    ^^

它们有 7 处不同,因此汉明距离是 7。

实现说明

汉明距离只对长度相同的序列有定义,所以在长度不同的序列之间计算它是行不通的。

Option 用来表示一个可能没有有用结果的计算 (例如因为错误或无效输入)。 如果你不熟悉Option,可以阅读这篇教程。 Option 是所谓的单子,它涵盖了一个“计算层面”的特性,在这里就是值可能不存在。 恰当使用单子可以写出非常简洁、优雅 且易读的代码。使用不当则很容易适得其反。 观看这个视频了解更多。

应该避免的常见坑

对于Option有几条经验法则:

  1. 不需要就别用。与其写成
def add1(x: Int): Option[Int] = Some(x + 1)

不如写成

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

(有Option.map可以对这类简单函数做映射, 所以不必用Option把它们弄得累赘)。 2. 如果并不真的需要,就不要“解包”。 通常有内置函数能实现你的目的。过早解包的迹象 是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. 单子可以用在 for 推导式里,效果拔群。 当你想“组合”多个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

准备好开始 汉明 了吗?

注册 Exercism,借助 95 个练习 和真人导师指导,学习并掌握 Scala,全部免费。