What are all three digit combinations? Let some of them be written by hand.
000, 001, 002 ... 009, 010, 011 ... 099, 100, 101 ... 998, 999
We finished just counting! We have listed all the numbers from 0 to 999. For an arbitrary number of digits, this generalizes directly: the upper limit is 10^n (exception), where n is the number of digits.
The rooms are specially designed in this way. It would be oddly strange if there was a possible combination of three digits that was not a real number, or if there was a three-digit number that could not be expressed by combining the three digits!
This offers a simple plan for me that simply includes arithmetic and does not require a deep understanding of Haskell *:
- Create a list of numbers from 0 to
10^n - Turn each number into a list of numbers.
Step 2 is the fun part. To extract the digits (in base 10) of a three-digit number, do this :
- Take the ratio and the remainder of your number relative to 100. Factor is the first digit of the number.
- Take the remainder from step 1 and take its coefficient and remainder with respect to 10. The factor is the second digit.
- The rest of step 2 was the third digit. This is the same as the ratio of quotient with respect to 1.
For an n-digit number, we take the factor n times, starting at 10^(n-1) and ending at 1 . Each time, we use the remainder of the last step as input to the next step. This suggests that our function, in order to turn a number into a list of digits, must be implemented as a fold: we will skip the remainder through the operation and create the list as we move. (I will leave this to you to find out how this algorithm changes if you are not in base 10!)
Now let's implement this idea. We want to calculate a certain number of digits, if necessary, with zero filling of a given number. What should be the type of digits ?
digits :: Int -> Int -> [Int]
Hmm, it takes a few digits and an integer and creates a list of integers representing the digits of the input integer. The list will contain single-digit integers, each of which will have one digit from the input number.
digits numberOfDigits theNumber = reverse $ fst $ foldr step ([], theNumber) powersOfTen where step exponent (digits, remainder) = let (digit, newRemainder) = remainder `divMod` exponent in (digit : digits, newRemainder) powersOfTen = [10^n | n <- [0..(numberOfDigits-1)]]
What is striking to me is that this code is very similar to my English description of arithmetic, which we wanted to perform. We generate a table with ten degrees due to the exposure numbers from 0 up. Then we add this table; at each step we put the factor in the list of numbers and send the remainder to the next step. We should reverse the list at the end due to the right to the left as it was built.
By the way, the template for generating a list, converting it, and then folding it back is the idiomatic thing to do in Haskell. He even had his own highest Falutin name, chylomorphism. GHC also knows about this template and can compile it into a complex cycle, optimizing the very existence of the list you are working with.
Test it out!
ghci> digits 3 123 [1, 2, 3] ghci> digits 5 10101 [1, 0, 1, 0, 1] ghci> digits 6 99 [0, 0, 0, 0, 9, 9]
It works like a charm! (Well, it’s wrong when numberOfDigits too small for theNumber , but don’t pay attention to it.) Now we just need to create a countable list of numbers on which to use digits .
combinationsOfDigits :: Int -> [[Int]] combinationsOfDigits numberOfDigits = map (digits numberOfDigits) [0..(10^numberOfDigits)-1]
... and we are done!
ghci> combinationsOfDigits 2 [[0,0],[0,1],[0,2],[0,3],[0,4],[0,5],[0,6],[0,7],[0,8],[0,9],[1,0],[1,1] ... [9,7],[9,8],[9,9]]
* For a version that requires a deep understanding of Haskell, see my other answer .