Exercism - Largest Series Product
This post shows you how to get Largest Series Product 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.
Classes
Classes define blueprints for objects. They can contain methods that work together to solve a problem.
class LargestSeriesProduct {
int largestProduct(String digits, int span) {
// Calculate largest product logic
return 0;
}
}
void main() {
LargestSeriesProduct calculator = LargestSeriesProduct();
int result = calculator.largestProduct("63915", 3);
print(result); // 162
}
ArgumentError
ArgumentError is thrown when a function receives an invalid argument. You can throw it to indicate that the input doesn’t meet the function’s requirements.
void main() {
int largestProduct(String digits, int span) {
// Validate span
if (span < 0) {
throw ArgumentError('span must not be negative');
}
if (span > digits.length) {
throw ArgumentError('span must be smaller than string length');
}
// Process...
return 0;
}
try {
largestProduct("123", 5); // Throws ArgumentError
} catch (e) {
print(e); // ArgumentError: span must be smaller than string length
}
}
Regular Expressions (RegExp)
Regular expressions allow you to match patterns in strings. The RegExp class and hasMatch() method are used to validate string formats.
void main() {
// Create regex pattern for digits only
RegExp digitPattern = RegExp(r'^\d*$');
// Check if string matches
print(digitPattern.hasMatch('123')); // true
print(digitPattern.hasMatch('63915')); // true
print(digitPattern.hasMatch('12a3')); // false (contains letter)
print(digitPattern.hasMatch('12 3')); // false (contains space)
// Use for validation
String digits = "63915";
if (!digitPattern.hasMatch(digits)) {
throw ArgumentError('digits input must only contain digits');
}
}
String substring() Method
The substring() method extracts a portion of a string. It takes a start index and optionally an end index. It’s perfect for extracting series of adjacent digits.
void main() {
String digits = "63915";
// Get substring from index to end
String rest = digits.substring(2);
print(rest); // "915"
// Get substring with start and end
String series1 = digits.substring(0, 3);
print(series1); // "639"
String series2 = digits.substring(1, 4);
print(series2); // "391"
// Extract all series of length 3
for (int i = 0; i <= digits.length - 3; i++) {
String series = digits.substring(i, i + 3);
print(series); // "639", "391", "915"
}
}
String split() Method
The split() method divides a string into a list of substrings. When called with an empty string '', it splits the string into individual characters.
void main() {
String series = "639";
// Split into individual characters
List<String> chars = series.split('');
print(chars); // ["6", "3", "9"]
// Use with map to convert to integers
List<int> numbers = series.split('').map(int.parse).toList();
print(numbers); // [6, 3, 9]
}
List generate() Method
The List.generate() method creates a list by calling a function for each index. It’s perfect for generating all possible series positions.
void main() {
String digits = "63915";
int span = 3;
// Generate all starting positions for series
List<int> positions = List.generate(digits.length - span + 1, (i) => i);
print(positions); // [0, 1, 2]
// Generate all series
List<String> series = List.generate(
digits.length - span + 1,
(i) => digits.substring(i, i + span)
);
print(series); // ["639", "391", "915"]
}
Iterable map() Method
The map() method transforms each element in an iterable. It returns a new iterable with transformed values. It’s used to convert strings to integers and calculate products.
void main() {
List<String> series = ["639", "391", "915"];
// Convert each series to list of integers
List<List<int>> numbers = series.map((s) => s.split('').map(int.parse).toList()).toList();
print(numbers); // [[6, 3, 9], [3, 9, 1], [9, 1, 5]]
// Calculate product of each series
List<int> products = series.map((s) {
return s.split('').map(int.parse).fold(1, (p, d) => p * d);
}).toList();
print(products); // [162, 27, 45]
}
int.parse() Method
The int.parse() method converts a string to an integer. It throws an exception if the string is not a valid integer.
void main() {
// Parse single digit
int digit = int.parse('6');
print(digit); // 6
// Parse multiple digits
int number = int.parse('639');
print(number); // 639
// Use with map to convert list of strings
List<String> chars = ['6', '3', '9'];
List<int> numbers = chars.map(int.parse).toList();
print(numbers); // [6, 3, 9]
}
List fold() Method
The fold() method reduces a list to a single value by applying a function to each element and an accumulator. It’s perfect for calculating products.
void main() {
List<int> numbers = [6, 3, 9];
// Calculate product using fold
int product = numbers.fold(1, (acc, value) => acc * value);
print(product); // 162 (6 × 3 × 9)
// Calculate sum using fold
int sum = numbers.fold(0, (acc, value) => acc + value);
print(sum); // 18 (6 + 3 + 9)
// Use with string conversion
String series = "639";
int product2 = series.split('').map(int.parse).fold(1, (p, d) => p * d);
print(product2); // 162
}
Iterable reduce() Method
The reduce() method reduces an iterable to a single value by applying a function to each element. It’s similar to fold() but doesn’t require an initial value.
void main() {
List<int> numbers = [162, 27, 45];
// Find maximum using reduce
int max = numbers.reduce((a, b) => a > b ? a : b);
print(max); // 162
// Find minimum using reduce
int min = numbers.reduce((a, b) => a < b ? a : b);
print(min); // 27
}
max() Function from dart:math
The max() function from dart:math returns the larger of two numbers. It’s more concise than using reduce() for finding maximum values.
import 'dart:math';
void main() {
List<int> numbers = [162, 27, 45];
// Find maximum using max function
int maximum = numbers.reduce(max);
print(maximum); // 162
// Compare two numbers
int larger = max(162, 27);
print(larger); // 162
}
Conditional (Ternary) Operator
The ternary operator (? :) provides a concise way to write if-else statements. It’s useful for simple conditional returns.
void main() {
int span = 0;
// Ternary operator
int result = span == 0 ? 1 : 0;
print(result); // 1
// Equivalent if-else
int result2;
if (span == 0) {
result2 = 1;
} else {
result2 = 0;
}
// Use in return statement
int calculate(int span) {
return span == 0 ? 1 : calculateProduct(span);
}
}
Method Chaining
Method chaining allows you to call multiple methods in sequence. Each method returns a value that can be used by the next method.
void main() {
String digits = "63915";
int span = 3;
// Chain methods together
int largest = List.generate(digits.length - span + 1, (i) => digits.substring(i, i + span))
.map((s) => s.split('').map(int.parse).fold(1, (p, d) => p * d))
.reduce(max);
print(largest); // 162
// Break down the chain:
// 1. Generate all series
// 2. Map each series to its product
// 3. Reduce to find maximum
}
Introduction
You work for a government agency that has intercepted a series of encrypted communication signals from a group of bank robbers. The signals contain a long sequence of digits. Your team needs to use various digital signal processing techniques to analyze the signals and identify any patterns that may indicate the planning of a heist.
Instructions
Your task is to look for patterns in the long sequence of digits in the encrypted signal.
The technique you’re going to use here is called the largest series product.
Let’s define a few terms, first.
- input: the sequence of digits that you need to analyze
- series: a sequence of adjacent digits (those that are next to each other) that is contained within the input
- span: how many digits long each series is
- product: what you get when you multiply numbers together
Example
Let’s work through an example, with the input “63915”.
To form a series, take adjacent digits in the original input.
If you are working with a span of 3, there will be three possible series:
- “639”
- “391”
- “915”
Then we need to calculate the product of each series:
- The product of the series “639” is 162 (6 × 3 × 9 = 162)
- The product of the series “391” is 27 (3 × 9 × 1 = 27)
- The product of the series “915” is 45 (9 × 1 × 5 = 45)
162 is bigger than both 27 and 45, so the largest series product of “63915” is from the series “639”. So the answer is 162.
How do we find the largest series product?
To find the largest series product:
- Validate inputs: Check that span is non-negative, span ≤ length, and digits contain only digits
- Handle edge case: If span is 0, return 1 (empty product)
- Generate all series: Create all possible adjacent series of the given span
- Calculate products: For each series, convert to integers and multiply all digits
- Find maximum: Return the largest product among all series
The key insight is using List.generate() to create all starting positions, then using substring() to extract each series, map() and fold() to calculate products, and reduce(max) to find the maximum.
For example, with “63915” and span 3:
- Generate positions: [0, 1, 2]
- Extract series: [“639”, “391”, “915”]
- Calculate products: [162, 27, 45]
- Find maximum: 162
Solution
import 'dart:math';
class LargestSeriesProduct {
int largestProduct(String digits, int span) {
if (span < 0) throw ArgumentError('span must not be negative');
if (span > digits.length) throw ArgumentError('span must be smaller than string length');
if (!RegExp(r'^\d*$').hasMatch(digits)) throw ArgumentError('digits input must only contain digits');
return span == 0
? 1
: List.generate(digits.length - span + 1, (i) => digits.substring(i, i + span))
.map((s) => s.split('').map(int.parse).fold(1, (p, d) => p * d))
.reduce(max);
}
}
Let’s break down the solution:
-
import 'dart:math'- Import max function:- Imports
max()function for finding maximum value - Used with
reduce()to find largest product
- Imports
-
class LargestSeriesProduct- Main class:- Encapsulates the largest product calculation
- Contains the main calculation method
-
int largestProduct(String digits, int span)- Main method:- Takes string of digits and span length
- Returns the largest product of any series
- Validates inputs before processing
-
if (span < 0) throw ArgumentError(...)- Validate span:- Checks that span is not negative
- Throws descriptive error if invalid
- Prevents negative span values
-
if (span > digits.length) throw ArgumentError(...)- Validate span length:- Checks that span doesn’t exceed string length
- Throws error if span is too large
- Example: span=5 for “123” is invalid
-
if (!RegExp(r'^\d*$').hasMatch(digits))- Validate digits:- Regular expression
^\d*$matches strings with only digits ^= start of string\d*= zero or more digits$= end of string- Throws error if string contains non-digits
- Regular expression
-
throw ArgumentError('digits input must only contain digits')- Error for invalid digits:- Provides clear error message
- Indicates what went wrong
-
return span == 0 ? 1 : ...- Handle edge case:- Ternary operator for concise conditional
- If span is 0, return 1 (empty product convention)
- Otherwise, calculate largest product
-
List.generate(digits.length - span + 1, (i) => ...)- Generate all series:- Creates list of all possible starting positions
digits.length - span + 1= number of possible series- Example: “63915” (length 5), span 3 → 5-3+1 = 3 positions [0, 1, 2]
-
digits.substring(i, i + span)- Extract series:- Gets substring starting at index i with length span
- Example: i=0, span=3 → “639”
- Example: i=1, span=3 → “391”
- Example: i=2, span=3 → “915”
-
.map((s) => ...)- Transform to products:- Maps each series string to its product
- Transforms list of strings to list of products
-
s.split('')- Split to characters:- Converts string to list of single characters
- Example: “639” → [“6”, “3”, “9”]
-
.map(int.parse)- Convert to integers:- Parses each character string to integer
- Example: [“6”, “3”, “9”] → [6, 3, 9]
-
.fold(1, (p, d) => p * d)- Calculate product:- Folds list to single product value
- Starts with 1 (multiplicative identity)
- Multiplies each digit with accumulator
- Example: [6, 3, 9] → 1×6×3×9 = 162
-
.reduce(max)- Find maximum:- Reduces list of products to maximum value
- Uses
max()function from dart:math - Example: [162, 27, 45] → 162
The solution efficiently finds the largest series product using method chaining to generate all series, calculate their products, and find the maximum. Input validation ensures the function handles edge cases and invalid inputs gracefully.
A video tutorial for this exercise is coming soon! In the meantime, check out my YouTube channel for more Dart and Flutter tutorials. 😉
Visit My YouTube Channel