Self-descriptive methods
Weekly challenge 107 — 5 April 2021
Week 107: 5 Apr 2021
Write a script to display the first three self-descriptive numbers. As per Wikipedia, the definition of Self-descriptive Number is an integer m that in a given base b is b digits long in which each digit d at position n (the most significant digit being at position 0 and the least significant at position b−1) counts how many instances of digit n are in m.
Example 1 Input: 3 Output: 1210, 2020, 21200 1210 is a four-digit self-descriptive number: position 0 has value 1 as there's only one 0 in the number position 1 has value 2 as there are two 1s in the number position 2 has value 1 as there's only one 2 in the number position 3 has value 0 as there is no 3 in the number
The Wikipedia entry is perhaps overcomplicated in that numbers here are essentially strings of digits rather denoting a value in some base. The definition thus boils down to:
A self-descriptive number is a string of digits in which the d'th digit (counting from 0) is a count of the number of ds in the string.
I therefore looped up from 1, counting the number of each digit 0 to 9 in the string and from that checked whether the number was self-descriptive.
That algorithm found the specified 3 numbers - 1210, 2020 and 21200 in negigible time, found the fourth (3211000) in around 10 seconds and the fifth (42101000) in about 10 minutes. I didn't go any further.
#!/usr/bin/perl # Blog: http://ccgi.campbellsmiths.force9.co.uk/challenge use v5.26; # The Weekly Challenge - 2021-04-05 use utf8; # Week 107 - task 1 - Self-descriptive numbers use warnings; # Peter Campbell Smith binmode STDOUT, ':utf8'; use Encode; self_descriptive_numbers(3); sub self_descriptive_numbers { my ($number, $position, @sd_numbers, @has, $limit, @occurs, $value, $last_index); # initialise $limit = $_[0]; @sd_numbers = (); N: for $number (1 .. 1e10) { # count occurrences of 0 - 9 $last_index = length($number) - 1; @has = (0, 0, 0, 0, 0, 0, 0, 0, 0, 0); for $position (0 .. $last_index) { $value = substr($number, $position, 1); # if any digit exceeds the no of digits then this is no good next N if $value > $last_index; $has[$value] ++; } # check if self_descriptive for $position (0 .. $last_index) { next N unless substr($number, $position, 1) == $has[$position]; } push @sd_numbers, $number; last if @sd_numbers == $limit; } say qq[\nInput: $limit]; say qq[Output: ] . join(', ', @sd_numbers); }
17 lines of code
I completed this challenge after the closing date
and it has not
been submitted to GitHub
Input: 3 Output: 1210, 2020, 21200
Any content of this website which has been created by Peter Campbell Smith is in the public domain