Calculating the average of a number's digits is a common programming exercise. For example, the number 123 has digits 1, 2, and 3, so the average is (1 + 2 + 3) / 3 = 2.0.
This guide covers three approaches: String Conversion for readability, Functional Programming for conciseness, and Pure Math for performance.
Using String Conversion
The most readable approach treats the number as a string of characters, allowing direct iteration over each digit.
def average_of_digits(n: int) -> float:
"""Calculate the average of digits in a number."""
digits_str = str(abs(n))
digits = [int(char) for char in digits_str]
return sum(digits) / len(digits)
print(average_of_digits(842)) # (8 + 4 + 2) / 3 = 4.666...
print(average_of_digits(-123)) # (1 + 2 + 3) / 3 = 2.0
print(average_of_digits(5)) # 5 / 1 = 5.0Output:
4.666666666666667
2.0
5.0Handling Edge Cases
def average_of_digits_safe(n: int) -> float | None:
"""Calculate average with edge case handling."""
if n == 0:
return 0.0
digits_str = str(abs(n))
digits = [int(char) for char in digits_str]
return sum(digits) / len(digits)
print(average_of_digits_safe(0)) # 0.0
print(average_of_digits_safe(100)) # (1 + 0 + 0) / 3 = 0.333...Using Functional Programming
For a more concise solution, use map() to convert characters to integers in a single expression.
def average_of_digits_functional(n: int) -> float:
"""Calculate average using map()."""
digits = list(map(int, str(abs(n))))
return sum(digits) / len(digits)
print(average_of_digits_functional(642)) # 4.0As a One-Liner
n = 12345
average = sum(map(int, str(abs(n)))) / len(str(abs(n)))
print(f"Average of digits in {n}: {average}")Output:
Average of digits in 12345: 3.0Using Pure Math
When performance is critical or memory allocation must be minimized, extract digits using mathematical operations. The modulo operator % gets the last digit, and integer division // removes it.
def average_of_digits_math(n: int) -> float:
"""Calculate average using mathematical operations only."""
n = abs(n)
if n == 0:
return 0.0
total = 0
count = 0
while n > 0:
digit = n % 10 # Extract last digit
total += digit
count += 1
n = n // 10 # Remove last digit
return total / count
print(average_of_digits_math(987)) # (9 + 8 + 7) / 3 = 8.0
print(average_of_digits_math(1000)) # (1 + 0 + 0 + 0) / 4 = 0.25Output:
8.0
0.25Extended Example: Statistics on Digits
You can extend this concept to calculate other statistics:
from statistics import mean, median, stdev
def digit_statistics(n: int) -> dict:
"""Calculate various statistics on a number's digits."""
digits = [int(d) for d in str(abs(n))]
stats = {
'digits': digits,
'count': len(digits),
'sum': sum(digits),
'mean': mean(digits),
'median': median(digits),
'min': min(digits),
'max': max(digits),
}
if len(digits) > 1:
stats['stdev'] = stdev(digits)
return stats
result = digit_statistics(9182736)
for key, value in result.items():
print(f"{key}: {value}")Output:
digits: [9, 1, 8, 2, 7, 3, 6]
count: 7
sum: 36
mean: 5.142857142857143
median: 6
min: 1
max: 9
stdev: 3.132015933791495Performance Comparison
import time
n = 12345678901234567890
def average_of_digits(n: int) -> float:
"""Calculate the average of digits in a number."""
digits_str = str(abs(n))
digits = [int(char) for char in digits_str]
return sum(digits) / len(digits)
def average_of_digits_math(n: int) -> float:
"""Calculate average using mathematical operations only."""
n = abs(n)
if n == 0:
return 0.0
total = 0
count = 0
while n > 0:
digit = n % 10 # Extract last digit
total += digit
count += 1
n = n // 10 # Remove last digit
return total / count
def average_of_digits_functional(n: int) -> float:
"""Calculate average using map()."""
digits = list(map(int, str(abs(n))))
return sum(digits) / len(digits)
def benchmark(func, n, iterations=100_000):
start = time.perf_counter()
for _ in range(iterations):
func(n)
return time.perf_counter() - start
print(f"String method: {benchmark(average_of_digits, n):.4f}s")
print(f"Functional: {benchmark(average_of_digits_functional, n):.4f}s")
print(f"Math method: {benchmark(average_of_digits_math, n):.4f}s")Typical Output:
String method: 0.6352s
Functional: 0.5082s
Math method: 0.4151sMethod Comparison
| Method | Readability | Performance | Best For |
|---|---|---|---|
| String Conversion | High | Good | General use, clarity |
Functional (map) |
High | Good | Concise code |
| Pure Math | Medium | Best | Performance-critical code |
Summary
- Use the string conversion method for most applications: it's readable and handles edge cases clearly.
- Use the functional approach with
map()when you prefer concise, one-liner solutions. - Use the pure math method only when performance is critical or memory allocation must be minimized.