Here's a way to count the unique digits in a number using a mostly functional style. There's an API method, count_unique_digits
:
def count_unique_digits(n)
if n < 0
raise Exception.new("can only handle numbers >= 0")
end
return count_unique_digits_iter([], 0, n)
end
This calls the main method, count_unique_digits_iter
. This is recursive, passing intermediate results as parameters to itself.
def count_unique_digits_iter(num_array, count, n)
new_digit = n % 10
new_digit_unique = ! num_array.include?(new_digit)
increment = new_digit_unique ? 1 : 0
if n < 10
return count + increment
end
if new_digit_unique
num_array.push(new_digit)
end
return count_unique_digits_iter(num_array, count + increment, n/10)
end
Given the methods, here's a method to count how often digits repeat in all the integers in a range:
def build_count_map(range)
count_map = Hash.new(0)
for i in range
old_count = count_map[count_unique_digits(i)]
count_map[count_unique_digits(i)] = old_count.succ
end
count_map
end
This counts all the digit repetitions of four digit numbers
count_map = build_count_map(1000 .. 9999)
for count in count_map.keys.sort
print "#{count}: #{count_map[count]}\n"
end
And here's the output:
1: 9
2: 567
3: 3888
4: 4536
(In the first version of this post, I omitted the unit tests.) Instead of a test framework, I used a homebrew checking method:
def check_method(method, input, expected)
if self.send(method, input) != expected
raise Exception.new("#{method}(#{input}):\n" +
"expected " + expected.inspect +
" but got " + self.send(method, input).inspect + "\n")
end
end
Which made it easy to plug in tests for count_unique_digits
def check_digits(input, expected)
check_method(:count_unique_digits, input, expected)
end
check_digits(0, 1)
check_digits(1, 1)
check_digits(10, 2)
check_digits(11, 1)
check_digits(123, 3)
check_digits(999, 1)
check_digits(1000, 2)
and tests for build_count_map
def check_count_map(input, expected)
check_method(:build_count_map, input, expected)
end
check_count_map(0 .. 0, {1 => 1})
check_count_map(0 .. 1, {1 => 2})
check_count_map(10 .. 20, {1 => 1, 2 => 10}) # only 11 has no repeated digits
check_count_map(10 .. 99, {1 => 9, 2 => 81}) # 11, 22, 33, ..., 99 are the doubles