مسیرها
/
Elixir
Elixir
/
تمرین‌ها
/
رمزگذاری DNA
رمزگذاری DNA

رمزگذاری DNA

تمرین یادگیری

مقدمه

بازگشت دمی

وقتی با بازگشت روی داده‌های قابل شمارش (فهرست‌ها، بیت‌استرینگ‌ها، رشته‌ها) کار می‌کنید، معمولاً دو دغدغه وجود دارد:

  • چه مقدار حافظه برای نگه‌داشتن ردِ فراخوانی‌های بازگشتی تابع لازم است
  • چگونه راه‌حل را به‌شکل کارآمد بسازیم

برای رسیدگی به این دغدغه‌ها می‌توان از یک انباره استفاده کرد.

انباره متغیری است که علاوه بر خود داده‌ها منتقل می‌شود. از آن برای انتقال وضعیت جاری اجرای تابع، از یک فراخوانی به فراخوانی بعدی، تا رسیدن به حالت پایه استفاده می‌شود. در حالت پایه، از انباره برای برگرداندن مقدار نهایی فراخوانی بازگشتی تابع استفاده می‌شود.

انباره را باید نویسنده‌ی تابع مقداردهی اولیه کند، نه کاربر تابع. برای این کار دو تابع تعریف کنید: یک تابع عمومی که فقط داده‌های لازم را به‌عنوان ورودی می‌گیرد و انباره را مقداردهی اولیه می‌کند و یک تابع خصوصی که انباره را هم می‌گیرد. در Elixir، الگوی رایجی است که نام تابع خصوصی را با do_ شروع کنند.

# Count the length of a list without an accumulator
def count([]), do: 0
def count([_head | tail]), do: 1 + count(tail)

# Count the length of a list with an accumulator
def count(list), do: do_count(list, 0)

defp do_count([], count), do: count
defp do_count([_head | tail], count), do: do_count(tail, count + 1)

استفاده از انباره به ما اجازه می‌دهد توابع بازگشتی را به توابع بازگشتی دمی تبدیل کنیم. تابع زمانی بازگشتی دمی است که آخرین عملیاتی که اجرا می‌کند، فراخوانی خودش باشد.

دستورالعمل‌ها

در آزمایشگاه تحقیقاتی DNA خود، روش‌های مختلفی را برای فشرده‌سازی داده‌های تحقیقیتان و صرفه‌جویی در فضای ذخیره‌سازی بررسی کرده‌اید. یکی از همکارانتان پیشنهاد می‌کند داده‌های DNA را به یک نمایش دودویی تبدیل کنید:

اسید نوکلئیک Code
یک فاصله 0000
A 0001
C 0010
G 0100
T 1000

روی این موضوع تأمل می‌کنید، چون این کار به‌طور بالقوه هزینه‌های ذخیره‌سازی داده‌های موردنیاز را نصف می‌کند، اما به قیمت کاهش خوانایی برای انسان تمام می‌شود. تصمیم می‌گیرید ماژولی بنویسید که داده‌هایتان را کدگذاری و رمزگشایی کند تا میزان صرفه‌جویی را بسنجید.

1. کدگذاری اسید نوکلئیک به مقدار دودویی

تابع encode_nucleotide/1 را طوری پیاده‌سازی کنید که کدپوینت اسید نوکلئیک را بپذیرد و مقدار عدد صحیح کد کدگذاری‌شده را برگرداند.

DNA.encode_nucleotide(?A)
# => 1
# (which is equal to 0b0001)

2. رمزگشایی مقدار دودویی به اسید نوکلئیک

تابع decode_nucleotide/1 را طوری پیاده‌سازی کنید که مقدار عدد صحیح کد کدگذاری‌شده را بپذیرد و کدپوینت اسید نوکلئیک را برگرداند.

DNA.decode_nucleotide(0b0001)
# => 65
# (which is equal to ?A)

3. کدگذاری یک charlist از DNA

تابع encode/1 را طوری پیاده‌سازی کنید که یک charlist نشان‌دهنده‌ی اسیدهای نوکلئیک و فاصله‌ها را بپذیرد و یک bitstring از داده‌های کدگذاری‌شده برگرداند.

DNA.encode(~c"AC GT")
# => <<18, 4, 8::size(4)>>

4. رمزگشایی یک bitstring از DNA

تابع decode/1 را طوری پیاده‌سازی کنید که یک bitstring نشان‌دهنده‌ی اسیدهای نوکلئیک و فاصله‌ها را بپذیرد و داده‌های رمزگشایی‌شده را به‌صورت یک charlist برگرداند.

DNA.decode(<<132, 2, 1::size(4)>>)
# => ~c"TG CA"
ویرایش از طریق GitHub این لینک در پنجره یا زبانه‌ی جدیدی باز می‌شود
Elixir Exercism

آماده‌اید رمزگذاری DNA را شروع کنید؟

در Exercism ثبت‌نام کنید تا Elixir را همراه با 58 مفهوم168 تمرین و مربی‌گری انسانی واقعی یاد بگیرید و در آن استاد شوید، همه‌ی این‌ها رایگان.