轨道
/
Scala
Scala
/
练习
/
核苷酸计数
核苷酸计数

核苷酸计数

中等

说明

我们每个人都从亲生父母那里继承了一套被称为 DNA 的化学指令,它们影响着我们身体是如何构成的。 所有已知的生命都依赖 DNA!

注意:完成这道练习并不需要了解任何关于核苷酸或 DNA 的知识。

DNA 是一条由其他化学物质组成的长链,其中最重要的是四种核苷酸:腺嘌呤、胞嘧啶、鸟嘌呤和胸腺嘧啶。 一条 DNA 链可以包含数十亿个这四种核苷酸,而它们出现的顺序非常重要! 我们把一小段 DNA 中这些核苷酸的顺序称为“DNA 序列”。

我们用这些核苷酸的有序集合来表示 DNA 序列,常见的做法是用一串字符,比如用 "ATTACG" 表示一段包含 6 个核苷酸的 DNA 序列。 'A' 代表腺嘌呤,'C' 代表胞嘧啶,'G' 代表鸟嘌呤,'T' 代表胸腺嘧啶。

给定一个表示 DNA 序列的字符串,统计其中每种核苷酸各有多少个。 如果字符串中包含不是 A、C、G 或 T 的字符,那么它就是无效的,你应该报错。

例如:

"GATTACA" -> 'A': 3, 'C': 1, 'G': 1, 'T': 2
"INVALID" -> error

Either的一个常见用途是表示一个可能出错的计算 (如果实际错误无关紧要,那么更简单的Option类型可能是更好的选择)。 没有错误时,结果通常是一个Right(助记:即“正确”的那个值), 而错误则是一个Left,例如一个包含错误信息的Left[String]。 注意,在 Scala 2.12 中,Either默认是右偏的,因此对于filter、map、flatMap这类操作,或者在 for 推导式中,它的行为都符合预期。 如果你不熟悉Either,可以阅读这篇教程。但要注意,这篇教程讲的是 2.12 之前的 Scala 版本。如果你用的是 Scala 2.12,可以放心忽略RightProjection,并省略.right。 Either是一种所谓的 Monad,它涵盖了一个“计算层面”,在这里就是错误处理。 正确使用 Monad 可以写出非常简洁、优雅且易读的代码。用得不恰当则很容易适得其反。 想了解更多,可以看看这个视频。

你应该避免的常见坑

对于Either,有几条经验法则:

  1. 不需要就不要用。与其写成
def add1(x: Int): Either[String, Int] = Right(x + 1)

不如写成

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

(有Either.map可以应用这类简单的函数, 所以不必用Either把它们弄得乱糟糟的)。 2. 不是真的需要,就不要“拆包”。 通常已经有现成的内置函数能满足你的目的。过早拆包的标志是isLeft/isRight或模式匹配。例如,与其写成

val x: Either[String, Int] = ...

if (x.isRight) x.right.get + 1 else x.left.get
// or
x match {
  case Right(n) => n + 1
  case Left(s) => s
}

不如写成

x fold (identity, _ + 1)
  1. Monad 可以放进 for 推导式里用,这才是王道。 当你想“组合”多个Either实例时,推荐这样做。与其写成
val xo: Either[String, Int] = ...
val yo: Either[String, Int] = ...
val zo: Either[String, 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,全部免费。