Наше тіло складається з клітин, які містять ДНК. Ці клітини регулярно зношуються і потребують заміни, а заміна відбувається шляхом поділу на дочірні клітини. Насправді, у середньому людське тіло за життя зазнає близько 10 квадрильйонів поділів клітин!
Коли клітини діляться, їхня ДНК теж реплікується. Іноді під час цього процесу трапляються помилки, і окремі ділянки ДНК отримують неправильну інформацію. Якщо порівняти два ланцюги ДНК і порахувати відмінності між ними, можна побачити, скільки помилок сталося. Це називається «відстанню Геммінга».
Відстань Геммінга корисна в багатьох галузях науки, не лише в біології, тож із цим терміном варто ознайомитися :)
Обчисліть відстань Гаммінга між двома ланцюгами ДНК.
Ми читаємо ДНК за допомогою літер C, A, G і T. Два ланцюги можуть мати такий вигляд:
GAGCCTACTAACGGGAT
CATCGTAATGACGGCCT
^ ^ ^ ^ ^ ^^
У них 7 відмінностей, а отже, відстань Гаммінга дорівнює 7.
Відстань Гаммінга визначена лише для послідовностей однакової довжини, тому спроба обчислити її між послідовностями різної довжини не повинна працювати.
Option використовують, щоб позначити обчислення, яке може не мати корисного результату (наприклад, через помилку або некоректні вхідні дані).
Якщо Option нам незнайомий, можемо прочитати цей посібник.
Option належить до так званих монад, які охоплюють «обчислювальний аспект», у цьому випадку можливу відсутність значення.
Правильне використання монад дає змогу отримати дуже лаконічний, але водночас елегантний і зрозумілий код. Неправильне використання легко може призвести до протилежного.
Щоб дізнатися більше, подивімося це відео.
Для Option є кілька простих правил:
Option не потрібен, не варто його використовувати. Замість цього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
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