gotchajavaMinor
Calculate the Hamming difference between two DNA strands
Viewed 0 times
thedifferencetwobetweenstrandscalculatednahamming
Problem
Write a program that can calculate the Hamming difference between two DNA strands.
GAGCCTACTAACGGGAT
CATCGTAATGACGGCCT
^ ^ ^ ^ ^ ^^
The Hamming distance between these two DNA strands is 7.
Test suite:
```
import static org.hamcrest.CoreMatchers.*;
import static org.junit.Assert.*;
import org.junit.Test;
public class HammingTest {
@Test
public void testNoDifferenceBetweenIdenticalStrands() {
assertThat(Hamming.compute("A", "A"), is(0));
}
@Test
public void testCompleteHammingDistanceOfForSingleNucleotideStrand() {
assertThat(Hamming.compute("A", "G"), is(1));
}
@Test
public void testCompleteHammingDistanceForSmallStrand() {
assertThat(Hamming.compute("AG", "CT"), is(2));
}
@Test
public void testSmallHammingDistance() {
assertThat(Hamming.compute("AT", "CT"), is(1));
}
@Test
public void testSmallHammingDistanceInLongerStrand() {
assertThat(Hamming.compute("GGACG", "GGTCG"), is(1));
}
@Test(expected = IllegalArgumentException.class)
public void testValidatesFirstStrandNotLonger() {
Hamming.compute("AAAG", "AAA");
}
@Test(expected = IllegalArgumentException.class)
public void testValidatesOtherStrandNotLonger() {
Hamming.compute("AAA", "AAAG");
}
@Test
public void testLargeHammingDistance() {
assertThat(Hamming.compute("GATACA", "GCATAA"), is(4));
}
@Test
GAGCCTACTAACGGGAT
CATCGTAATGACGGCCT
^ ^ ^ ^ ^ ^^
The Hamming distance between these two DNA strands is 7.
import java.util.Optional;
public class Hamming {
public static int compute(String s1, String s2) {
validateInputs(s1, s2);
int hammingDistance = 0;
int stringLength = s1.length();
for (int i = 0; i < stringLength; i++) {
if (s1.charAt(i) != s2.charAt(i)) {
hammingDistance++;
}
}
return hammingDistance;
}
private static void validateInputs(String s1, String s2) {
if (s1.length() != s2.length()) {
throw new IllegalArgumentException();
}
}
}Test suite:
```
import static org.hamcrest.CoreMatchers.*;
import static org.junit.Assert.*;
import org.junit.Test;
public class HammingTest {
@Test
public void testNoDifferenceBetweenIdenticalStrands() {
assertThat(Hamming.compute("A", "A"), is(0));
}
@Test
public void testCompleteHammingDistanceOfForSingleNucleotideStrand() {
assertThat(Hamming.compute("A", "G"), is(1));
}
@Test
public void testCompleteHammingDistanceForSmallStrand() {
assertThat(Hamming.compute("AG", "CT"), is(2));
}
@Test
public void testSmallHammingDistance() {
assertThat(Hamming.compute("AT", "CT"), is(1));
}
@Test
public void testSmallHammingDistanceInLongerStrand() {
assertThat(Hamming.compute("GGACG", "GGTCG"), is(1));
}
@Test(expected = IllegalArgumentException.class)
public void testValidatesFirstStrandNotLonger() {
Hamming.compute("AAAG", "AAA");
}
@Test(expected = IllegalArgumentException.class)
public void testValidatesOtherStrandNotLonger() {
Hamming.compute("AAA", "AAAG");
}
@Test
public void testLargeHammingDistance() {
assertThat(Hamming.compute("GATACA", "GCATAA"), is(4));
}
@Test
Solution
Your code is really all that there is to it. It is clear and concise: one method to validate the input (
A couple of comments:
-
In case of inputs of different length, you are (rightfully) throwing a
This is a generic
-
To resemble what is done by the existing
This has the advantage that the method name is now self-documenting and it is returning the correct value, which means we can chain the result (just like
-
If you're using Java 8, you could write this a bit shorter using the Stream API:
It maps each index to 0 or 1 based on whether the two input Strings have equal characters at that index, and sums the result.
validateInputs) and the rest of the method to calculate the Hamming distance with a simple loop.A couple of comments:
-
In case of inputs of different length, you are (rightfully) throwing a
IllegalArgumentException like this:if (s1.length() != s2.length()) {
throw new IllegalArgumentException();
}This is a generic
IllegalArgumentException with no message. You might want to add a message so that it is clearer to the caller what went wrong; it would also help the debugging (imagine a bigger application).-
To resemble what is done by the existing
Objects class, you could rename your validating method to requireSameLength and make it return the length:private static int requireSameLength(String s1, String s2) {
if (s1.length() != s2.length()) {
throw new IllegalArgumentException();
}
return s1.length();
}This has the advantage that the method name is now self-documenting and it is returning the correct value, which means we can chain the result (just like
requireNonNull which returns the non-null value or throws an exception).-
import java.util.Optional; is not needed, you aren't using it.- Consider making the class
finalsince it looks like a utility class (only public static methods).
If you're using Java 8, you could write this a bit shorter using the Stream API:
public static int compute(String s1, String s2) {
int length = requireSameLength(s1, s2);
return IntStream.range(0, length).map(i -> s1.charAt(i) == s2.charAt(i) ? 0 : 1).sum();
}
private static int requireSameLength(String s1, String s2) {
if (s1.length() != s2.length()) {
throw new IllegalArgumentException();
}
return s1.length();
}It maps each index to 0 or 1 based on whether the two input Strings have equal characters at that index, and sums the result.
Code Snippets
if (s1.length() != s2.length()) {
throw new IllegalArgumentException();
}private static int requireSameLength(String s1, String s2) {
if (s1.length() != s2.length()) {
throw new IllegalArgumentException();
}
return s1.length();
}public static int compute(String s1, String s2) {
int length = requireSameLength(s1, s2);
return IntStream.range(0, length).map(i -> s1.charAt(i) == s2.charAt(i) ? 0 : 1).sum();
}
private static int requireSameLength(String s1, String s2) {
if (s1.length() != s2.length()) {
throw new IllegalArgumentException();
}
return s1.length();
}Context
StackExchange Code Review Q#127299, answer score: 3
Revisions (0)
No revisions yet.