This problem is from Advent of Code day 4 (part 1). The problem is to find the number of ints in the given range satisfying:
- all digits are non decreasing
- there is at least one group of at least two equal digits in a row
combinations
only generates non-decreasing sequences; for example:
λ> combinations 2 ['1'..'3']
["11","12","13","22","23","33"]
The algorithm generates all non-decreasing combinations from ['0'..'9']
, then checks that there's at least one repeating character, that there are no leading zeros, and that the number is in range. Running it with the input 125730-579381
correctly prints 2081
.
The main things I want to know about are whether there's a way to improve the algorithm, and whether the readability is good.
import Data.List (tails, group)
import Control.Arrow
import Control.Monad
-- all non-decreasing combinations of k from xs
combinations :: Int -> [a] -> [[a]]
combinations 0 _ = [[]]
combinations k xs = do
xs'@(x:_) <- tails xs
map (x:) $ combinations (pred k) xs'
-- return True iff all predicates are satisfied
allF :: [a -> Bool] -> a -> Bool
allF fs x = and $ map ($ x) fs
-- all ints within the range satisfying:
-- strictly increasing digits
-- at least one sequence of exactly 2 of the same digit
solve :: Int -> Int -> Int
solve low hi = length . takeWhile (<= hi) . dropWhile (< low) . map read .
filter (allF [hasDouble, noLeadingZeros]) $ combinations 6 ['0'..'9']
where hasDouble = any ((> 1) . length) . group
noLeadingZeros = (/= '0') . head
main :: IO ()
main = do
(low, high) <- join (***) read <$> second tail <$> span (/= '-') <$> getLine
print $ solve low high
combinations
generates only non-decreasing sequences so there's no need to check that condition a second time in my algorithm. I think that this is faster than generating all numbers in the range and checking that they're ascending. In part two of the question (not shown on the link until you solve part 1), the requirement changes to be exactly == 2 instead of at least 2. I will update my question. \$\endgroup\$noLeadingZeroes
part is because this question deals with numbers instead of strings of digits. If I didn't include that part, my algorithm would deem000000
as good when in reality that would just be0
which has no repeating digits. \$\endgroup\$