""" Combinatoric selections Problem 47 The first two consecutive numbers to have two distinct prime factors are: 14 = 2 x 7 15 = 3 x 5 The first three consecutive numbers to have three distinct prime factors are: 644 = 2² x 7 x 23 645 = 3 x 5 x 43 646 = 2 x 17 x 19. Find the first four consecutive integers to have four distinct prime factors each. What is the first of these numbers? """ from functools import lru_cache def unique_prime_factors(n: int) -> set: """ Find unique prime factors of an integer. Tests include sorting because only the set matters, not the order in which it is produced. >>> sorted(set(unique_prime_factors(14))) [2, 7] >>> sorted(set(unique_prime_factors(644))) [2, 7, 23] >>> sorted(set(unique_prime_factors(646))) [2, 17, 19] """ i = 2 factors = set() while i * i <= n: if n % i: i += 1 else: n //= i factors.add(i) if n > 1: factors.add(n) return factors @lru_cache def upf_len(num: int) -> int: """ Memoize upf() length results for a given value. >>> upf_len(14) 2 """ return len(unique_prime_factors(num)) def equality(iterable: list) -> bool: """ Check the equality of ALL elements in an iterable >>> equality([1, 2, 3, 4]) False >>> equality([2, 2, 2, 2]) True >>> equality([1, 2, 3, 2, 1]) False """ return len(set(iterable)) in (0, 1) def run(n: int) -> list[int]: """ Runs core process to find problem solution. >>> run(3) [644, 645, 646] """ # Incrementor variable for our group list comprehension. # This is the first number in each list of values # to test. base = 2 while True: # Increment each value of a generated range group = [base + i for i in range(n)] # Run elements through the unique_prime_factors function # Append our target number to the end. checker = [upf_len(x) for x in group] checker.append(n) # If all numbers in the list are equal, return the group variable. if equality(checker): return group # Increment our base variable by 1 base += 1 def solution(n: int = 4) -> int | None: """Return the first value of the first four consecutive integers to have four distinct prime factors each. >>> solution() 134043 """ results = run(n) return results[0] if len(results) else None if __name__ == "__main__": print(solution())