This question is part of a series solving the Rosalind challenges. For the previous question in this series, see The Genetic Code. The repository with all my up-to-date solutions so far can be found here.
Problem: HAMM
Given two strings \$s\$ and \$t\$ of equal length, the Hamming distance between \$s\$ and \$t\$, denoted \$d_H(s,t)\$, is the number of corresponding symbols that differ in \$s\$ and \$t\$.
Given:
Two DNA strings \$s\$ and \$t\$ of equal length (not exceeding 1 kbp).
Return:
The Hamming distance \$d_H(s,t)\$.
Sample Dataset:
GAGCCTACTAACGGGAT
CATCGTAATGACGGCCT
Sample Output:
7
My solution solves the sample dataset and the actual dataset given.
Dataset:
TGGGAGTTTAATGTCCCCATAAGGTGCCCGTATACGTGTAGTCGTAATCCGTACTCGTGGTCGTTGATTCGGGCGGATCCAGCTGCTGTGCCGGGTTCTCCCCTGGACTTGAGTGCTGAATAAGTTGCTGTCCCCGCTCACCGTCTAAGCCTGTCCGTTACAAATTGCTGGTCGACCATAACCCTGCGTACCGCCAGGAGCGTCGAGTCGCCCGGGAATTTCGGCGCAGAGGAATGGGATTGCTTCAAATATTATGTATCTGCCATTCAGTTTTGAGCGTCTTCGTGTCACTGTACCTGCGCCATGAAGGCTCAAATCACCCGCTCAGACAGGACCATCCCAAGTTACTGCACTTGTGGACGGGAGCGTCATCGGTTGGCATATATTGCCTCTATTGTCGTTGGGATGAAGTCCTAACCCTACCCTGTCTGGGACTCCTTTCCTGCCAGGGATTGAGCCATGATCCTTCTGTGGTCTATGTTTCGGTTACCATTATTGGCTTTGAGAGCGCCCCGGTACGGTACGCTTCCGGATCCGACCTTGGCATCATGAGTCGTGACCAACTGCTTTAAGCTTATAGGGGCCCATTAAGACGGCGCGGATCTTGTGTTGCGATGTTCTGTCGCAGGTGTATCAAGTACACTCGACGGCCCTGCTGGGGCTAATAACTCTACTGGCTATGGCGTAAGCTGGGCCGAGACGGCTCCTCGGAGCGGTCGCCCATGGATGAGACGAATGCAAACCTGTATATTCCACTCCACCCTAGAGGCCTTCTGGCCTGACTGTTACCTGAGACTGTGAACACCGATACAAGGCTGTGCTCATGACCAGTTGCCAGTTCTAAACAACATAGTCATCATGATTTGAGTCGCCAAGAGACTTGCTTTCCGAGACGGAATGAGCAAAGAGGCAGGCTTCGTCCTAAGTGGACCCGATTGCGTTTTACGAGGGGTGCCTTCGCGATGCGATTGTGAC
TACTCAATCCTCGTTACAACTAGGTGCCCGAAGTCAAGTAGCTCTGCCGCACGTCCGTGGTCATCGAGGGATGTGGATGCGGCAGCGGGGTCAGCTCGTCTCGTGCCAGTGTATATACGACTAAATACTGTCATCGCTCGCGGGCTGACCCTTTGCGTGGCACAGTGTTCCCCAAGCCTATCCATGCTCTCAGGGAGCAGCGTCTACCCGACCGCCGCTTATGGTGTGTAAGACTGCTTATGGTTCAAGACGGATCAAATGCACATTAATTTCGCAGCGTGATGATATTACACTACCTTCTGCATTGACGTTCAACTACACAAGTCGGAGCGGTCTATCCCATAGTGCAGTGCGCTTAGGTTGAAGCGTGAACGTTTATCAGTTATACCCTTCATTGTCCTCGAGGTGGTGTCATAAGGCTATGCTGCATGCCTCTCCGACCCTGCGAGATATTCTCCGTTTGTGCTTATGTATTCCCTGGTTCTCCTTAGTATAACCCTTTTTTCTGTGCTCCCCGACCTCGCAGTTCCGGCCAGTGCTTGCGTAACATGAGCAGTTACCTTAGTCATTACGCTTGGTAGTTCCCATTAGGAAGGCATGTATTTCGAGTTGCGGGATGGTTTGGGATGTGTGGCAAGATGTAAGGACCGCGTTGGTTACTCGATGAGACAAGCCAGGCACCGAACATCCTCGGGTCATCCGAATCATCCGAATGGTCGGCCACCGATCTGACGTGTGCCAACCCGTGGATGCCAGGCATCGTTAGAGGTATTTACCCTTGACTGTTATCTCGGAACGAGAACAACGTCAAATCCTTGCCCTTTTGATAACGGAGGACTACTATACTACCTAGTCATACCTATATCCGTCGCAAGGAATCTGAAATACCCGGACATAGAGAGAAAACAATAACACTGTGTCCGAAGAGGACTGTCTGGCCTTTCATTATTGATAACCGCGCAATGGCAGTTGGAC
Output:
456
app/HAMM.rb:
require_relative '../lib/Validation'
def HammingDistance(left, right)
v = Validation.new()
v.EqualSize(left, right)
distance = 0
for index in 0..left.length - 1
distance += 1 unless left[index] == right[index]
end
distance
end
first = gets.chomp
second = gets.chomp
puts HammingDistance(first, second)
Yes, I've re-arranged my project files. There are 4 folders:
- app
All applications, the 'end' solutions.
- bnc
Benchmarks.
- lib
Library with functions for applications.
- tst
Tests for the library, later possibly for the applications as well.
The given code makes use of one library file which is tested in two different ways.
Library:
lib/Validation.rb
class Validation
def Numeric(input)
raise ArgumentError, 'Argument is not numeric' unless input.is_a?(Numeric)
end
def Uppercase(input)
raise ArgumentError, 'Argument is not uppercase' unless input == input.upcase
end
def EqualSize(left, right)
raise ArgumentError, 'Arguments are not of equal size' unless left.size == right.size
end
end
Tests:
tst/Validation_tests.rb
Dir["../lib/*.rb"].each {|file| require file }
arr1 = [0, 1, 2, 3]
arr2 = [1, 2, 3, 4]
upp = "UPPER"
low = "LOWER"
num = 42
nums = "42"
n = Validation.new
n.EqualSize(arr1, arr2)
n.EqualSize(upp, low)
n.Uppercase(upp)
n.Numeric(num)
tst/Validation_unittests.rb
require 'rspec'
require_relative '../lib/Validation'
v = Validation.new()
describe "Size verification with empty right" do
it "raises" do
expect { v.EqualSize([1], []) }.to raise_error(ArgumentError)
end
end
describe "Size verification with left right" do
it "raises" do
expect { v.EqualSize([], [1]) }.to raise_error(ArgumentError)
end
end
describe "Size verification with both empty" do
it "succeeds" do
expect { v.EqualSize([], []) }.not_to raise_error
end
end
describe "Size verification with size 1, different values" do
it "succeeds" do
expect { v.EqualSize([1], [0]) }.not_to raise_error
end
end
describe "Size verification with both size 1, same values" do
it "succeeds" do
expect { v.EqualSize([1], [1]) }.not_to raise_error
end
end
Basically, I can now calculate the Hamming distance while validating the input. The Hamming distance is important in bioinformatics because it allows us to count mutations in DNA and the like.
The validation library will likely grow in size, so I better get it done right from the start to avoid a lot of work later on.
With all this validating going on I'm more than moderately concerned about the naming of it all. Names should be clear, but not overly verbose. It's Ruby, not C#.
Re-usability and idiomaticness are also major concerns.