Hamming

Hamming

سهل

مقدمة

يتكوّن جسمك من خلايا تحتوي على DNA. تبلى هذه الخلايا بانتظام وتحتاج إلى استبدال، وهو ما تحققه بالانقسام إلى خلايا وليدة. في الواقع، يمرّ جسم الإنسان العادي بنحو 10 كوادريليون انقسام خلوي خلال حياته!

وعندما تنقسم الخلايا، يتضاعف الـ DNA فيها أيضًا. وأحيانًا تحدث أخطاء أثناء هذه العملية، فتُشفَّر قطع منفردة من الـ DNA بمعلومات غير صحيحة. وإذا قارنّا بين شريطين من الـ DNA وعددنا الفروق بينهما، أمكننا أن نرى كم من الأخطاء قد وقع. ويُعرف هذا باسم "Hamming distance".

إن مسافة "Hamming distance" مفيدة في مجالات علمية كثيرة، لا في علم الأحياء فحسب، لذا فهي عبارة جيدة أن تألفها :)

التعليمات

احسب مسافة هامينغ بين سلسلتَي DNA نصيتين.

نقرأ DNA باستخدام الحروف C وA وG وT. قد تبدو سلسلتان نصيتان هكذا:

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

مستعد لبدء Hamming؟

سجّل في Exercism لتتعلّم وتتقن Scala عبر 95 تمرينًا، وإرشاد بشري حقيقي، وكل ذلك مجانًا.