Table of Contents
This was a relatively quick little problem to calculate the Hamming distance between two DNA strings. The problem boiled down to determining the number of differences between two charlists of the same length. A quick fun one! As a bonus, I show how to do a pull request on the Exercism Elixir repo in the live stream video.
Live solution video
This is my daily live stream video solution to this problem. Sorry about the out of sync audio towards the end of the video, I think my CPU was overloaded by the video encoding and I’ll need to adjust my settings before the stream tomorrow.
- Video available here: https://youtu.be/uVkMXwR-5aQ
- Also streaming on Twitch: https://www.twitch.tv/percygrunwald
Explanation of the solution
Function to calculate the Hamming distance between two charlists
The main part of this challenge was implementing a function that would take in two charlists (list of integer character codes) of equal length and return the number of places in which the lists differ. For example 'GAT'
and 'TAG'
should have a distance of 2
because 2 characters differ: the first character and the last character.
Basically we need some way to enumerate through the corresponding characters in the list and increment a counter if they are different and leave the counter the same if the characters are the same:
Character 1: {G, T} => chars different => increment the accumulator from 0 to 1
Character 2: {A, A} => chars same => leave accumulator the same
Character 3: {T, G} => chars different => increment the accumulator from 1 to 2
In order for us to easily compare the nth
character of both charlists, I made use of Enum.zip/2
:
# 71 is the charcode for G, 84 is the charcode for T, etc.
iex> Enum.zip('GAT', 'TAG')
[{71, 84}, {65, 65}, {84, 71}]
After zipping the lists, we can easily compare the nth
character of both lists and increment a counter as required by using Enum.reduce/3
:
Enum.zip(strand1, strand2)
|> Enum.reduce(0, fn {char1, char2}, acc ->
if char1 != char2 do
acc + 1
else
acc
end
end)
Full solution in text form
Here’s the full solution in text form, in case you want to look over the final product:
defmodule Hamming do
@doc """
Returns number of differences between two strands of DNA, known as the Hamming Distance.
## Examples
iex> Hamming.hamming_distance('AAGTCATA', 'TAGCGATC')
{:ok, 4}
"""
@spec hamming_distance([char], [char]) :: {:ok, non_neg_integer} | {:error, String.t()}
def hamming_distance(strand1, strand2) when length(strand1) == length(strand2) do
hamming_distance =
Enum.zip(strand1, strand2)
|> Enum.reduce(0, fn {char1, char2}, acc ->
if char1 != char2 do
acc + 1
else
acc
end
end)
{:ok, hamming_distance}
end
def hamming_distance(_strand1, _strand2), do: {:error, "Lists must be the same length"}
end