Exercism - Hamming
This post shows you how to get Hamming exercise of Exercism.
Preparation
Before we click on our next exercise, let’s see what concepts of DART we need to consider

So we need to use the following concepts.
List.generate
The List.generate method creates a list of a specified length by calling a function for each index. It’s perfect for creating lists based on calculations.
void main() {
// Generate list based on index
List<int> numbers = List.generate(5, (i) => i * 2);
print(numbers); // [0, 2, 4, 6, 8]
// Generate with conditional
List<int> values = List.generate(3, (i) => i > 1 ? 1 : 0);
print(values); // [0, 0, 1]
}
String Indexing
Strings in Dart can be accessed by index to get individual characters. You can compare characters at the same position in different strings.
void main() {
String s1 = "ABC";
String s2 = "ABD";
// Access by index
print(s1[0]); // 'A'
print(s1[2]); // 'C'
// Compare characters at same position
bool different = s1[2] != s2[2];
print(different); // true (C != D)
}
Comparison Operators
Comparison operators allow you to check if values are equal or different. The != operator checks for inequality.
void main() {
char a = 'A';
char b = 'B';
// Equality
bool equal = a == b;
print(equal); // false
// Inequality
bool notEqual = a != b;
print(notEqual); // true
}
Fold Method
The fold method is used to reduce a collection to a single value by iteratively combining each element with an existing value using a provided function.
void main() {
List<int> numbers = [1, 2, 3, 4];
// Sum all numbers
int sum = numbers.fold(0, (total, number) => total + number);
print(sum); // 10
// Count with initial value
int count = numbers.fold(0, (sum, val) => sum + val);
print(count); // 10
}
ArgumentError
ArgumentError is used to signal that an argument passed to a function is invalid. It’s part of Dart’s exception system.
void main() {
void validate(String s1, String s2) {
if (s1.length != s2.length) {
throw ArgumentError('strands must be of equal length');
}
}
try {
validate("ABC", "AB");
} catch (e) {
print(e); // ArgumentError: strands must be of equal length
}
}
Conditional (Ternary) Operator
The conditional operator ? : is a shorthand for if-else statements. It’s useful for concise conditional expressions.
void main() {
char a = 'A';
char b = 'B';
// Ternary operator
int result = a != b ? 1 : 0;
print(result); // 1 (they're different)
// Used in list generation
List<int> differences = List.generate(3, (i) => a != b ? 1 : 0);
print(differences); // [1, 1, 1]
}
Introduction
Your body is made up of cells that contain DNA. Those cells regularly wear out and need replacing, which they achieve by dividing into daughter cells. In fact, the average human body experiences about 10 quadrillion cell divisions in a lifetime!
When cells divide, their DNA replicates too. Sometimes during this process mistakes happen and single pieces of DNA get encoded with the incorrect information. If we compare two strands of DNA and count the differences between them, we can see how many mistakes occurred. This is known as the “Hamming distance”.
The Hamming distance is useful in many areas of science, not just biology, so it’s a nice phrase to be familiar with :)
Instructions
Calculate the Hamming distance between two DNA strands.
We read DNA using the letters C, A, G and T. Two strands might look like this:
GAGCCTACTAACGGGAT
CATCGTAATGACGGCCT
^ ^ ^ ^ ^ ^^
They have 7 differences, and therefore the Hamming distance is 7.
Implementation notes
The Hamming distance is only defined for sequences of equal length, so an attempt to calculate it between sequences of different lengths should not work.
What is Hamming distance?
The Hamming distance between two strings of equal length is the number of positions at which the corresponding symbols are different. In other words, it measures the minimum number of substitutions required to change one string into the other, or the minimum number of errors that could have transformed one string into the other.
The Hamming distance is named after Richard Hamming, who introduced it in his fundamental paper on error-detecting and error-correcting codes. It’s widely used in information theory, coding theory, cryptography, and bioinformatics.
— Wikipedia
How can we calculate Hamming distance?
To calculate the Hamming distance between two DNA strands:
- Check that both strands have the same length (throw an error if not)
- Compare each character at the same position in both strands
- Count how many positions have different characters
- Return the count
For example, comparing “GAGCCTACTAACGGGAT” and “CATCGTAATGACGGCCT”:
- Position 0: G != C → difference
- Position 1: A == A → same
- Position 2: G != T → difference
- And so on…
- Total: 7 differences
⚠️ Old Solution (No Longer Works)
Previously, the solution used asMap(), entries, and where with complex logic. Here’s what the old solution looked like:
class Hamming {
int distance(String strandL, String strandR) {
if(strandL.isEmpty ^ strandR.isEmpty) {
throw ArgumentError("no strand must be empty");
}
if(strandL.length != strandR.length) {
throw ArgumentError("left and right strands must be equal length");
}
return strandL.split('').asMap().entries.where((e) => e.value != strandR.split('')[e.key]).length;
}
}
Why This Solution Doesn’t Work Anymore
The old solution has several issues:
-
XOR operator for empty check: The
^(XOR) operator checks if exactly one strand is empty, but this is unnecessary. The length check already handles this case. The XOR logic is confusing and doesn’t add value. -
Inefficient string splitting: The solution calls
split('')twice - once forstrandLand once forstrandRinside thewhereclause. This is inefficient and creates unnecessary intermediate lists. -
Complex chaining: The combination of
asMap(),entries, andwheremakes the code hard to read and understand. -
Redundant empty check: The empty check with XOR is redundant since empty strings have length 0, which would be caught by the length check anyway.
The exercise now requires:
- Simpler, more efficient code using
List.generateand direct string indexing - Using
foldto sum differences instead of filtering and counting - Removing unnecessary empty string checks (length check is sufficient)
- More readable code that’s easier to understand and maintain
Solution
class Hamming {
int distance(String s1, String s2) {
if (s1.length != s2.length) {
throw ArgumentError('strands must be of equal length');
}
return List.generate(s1.length, (i) => s1[i] != s2[i] ? 1 : 0)
.fold(0, (sum, val) => sum + val);
}
}
Let’s break down the solution:
-
if (s1.length != s2.length)- Validates that both strands have the same length:- If lengths differ, throws an
ArgumentErrorwith a descriptive message - This single check handles all edge cases including empty strings
- If lengths differ, throws an
-
List.generate(s1.length, (i) => ...)- Creates a list with one element for each position:s1.lengthdetermines how many elements to generate- For each index
i, comparess1[i]withs2[i] - Uses ternary operator: if characters differ, returns 1; otherwise returns 0
- This creates a list of 1s and 0s, where 1 represents a difference
-
.fold(0, (sum, val) => sum + val)- Sums all the values in the list:- Starts with 0 as the initial value
- For each value in the list, adds it to the running sum
- The final sum is the total number of differences (Hamming distance)
The solution is more efficient, readable, and follows modern Dart best practices by using List.generate for iteration and fold for accumulation.
You can watch this tutorial on YouTube. So don’t forget to like and subscribe. 😉
Watch on YouTube