def curious_fractions(numbers: Iterable[int]) -> Iterable[Fraction]: fractions_parts = permutations(numbers, r=2) filtered_fractions_parts = star_filter( non_trivial_fraction, star_filter(operator.lt, fractions_parts)) for numerator, denominator in filtered_fractions_parts: numerator_digits = list(number_to_digits(numerator)) denominator_digits = list(number_to_digits(denominator)) try: common_digit, = set(numerator_digits) & set(denominator_digits) except ValueError: continue else: cancelled_numerator_digits = numerator_digits[:] cancelled_numerator_digits.remove(common_digit) cancelled_denominator_digits = denominator_digits[:] cancelled_denominator_digits.remove(common_digit) cancelled_numerator = digits_to_number(cancelled_numerator_digits) cancelled_denominator = digits_to_number( cancelled_denominator_digits) fraction = Fraction(numerator, denominator) cancelled_fraction = Fraction(cancelled_numerator, cancelled_denominator) fraction_is_curious = fraction == cancelled_fraction if fraction_is_curious: yield fraction
def square_root_convergents(stop: int) -> Iterable[bool]: for expansion in square_root_expansions(stop): numerator_digits_count = capacity(number_to_digits( expansion.numerator)) denominator_digits_count = capacity( number_to_digits(expansion.denominator)) yield numerator_digits_count > denominator_digits_count
def permuted_multiples(max_multiplier: int) -> Iterator[int]: for number in count(1): sorted_digits = sorted(number_to_digits(number)) for multiplier in range(2, max_multiplier + 1): multiplied_number = multiplier * number if sorted(number_to_digits(multiplied_number)) != sorted_digits: break else: yield number
def prime_permutations(*, start: int, stop: int, increment: int) -> Iterable[Tuple[int, int, int]]: prime_numbers_set = set(filter(partial(operator.le, start), prime_numbers(stop))) for number in filter(partial(operator.ge, 10_000 - increment * 2), prime_numbers_set): sorted_digits = sorted(number_to_digits(number)) second_number = number + increment third_number = second_number + increment second_number_digits = sorted(number_to_digits(second_number)) third_number_digits = sorted(number_to_digits(third_number)) if sorted_digits == second_number_digits == third_number_digits: if second_number in prime_numbers_set and third_number in prime_numbers_set: yield number, second_number, third_number
def is_pandigital(number: int) -> bool: digits = list(number_to_digits(number)) digits_set = set(digits) if len(digits) > len(digits_set): return False max_digit = max(digits_set) return not (pandigits[max_digit] ^ digits_set)
def digits_sums(*, start: int = 1, stop: int, step: int = 1) -> Iterable[int]: if stop == 2: return 1, bases = filterfalse(ends_with_zero, range(start, stop, step)) exponents = range(2, stop) for base, exponent in product(bases, exponents): yield sum(number_to_digits(base**exponent))
def pandigital_multiples(digits: Collection[int]) -> Iterator[int]: position_stop = ceil(len(digits) / 2) for digits in permutations(digits): for position in range(1, position_stop): base_digits = digits[:position] base = digits_to_number(base_digits) base_digits_set = set(base_digits) tail_start = position for multiplier in range(2, 10): tail = ''.join(map(str, digits[tail_start:])) if not tail: continue step = base * multiplier step_digits = list(number_to_digits(step)) step_digits_set = set(step_digits) step_digits_count = len(step_digits) if step_digits_count < len(step_digits_set): break if step_digits_set & base_digits_set: break if not tail.startswith(str(step)): break tail_start += step_digits_count else: yield digits_to_number(digits)
def circular(prime_number: int) -> bool: digits = tuple(number_to_digits(prime_number)) rotated_digits = (rotate(digits, position) for position in range(len(digits))) for rotated_prime in map(digits_to_number, rotated_digits): if rotated_prime not in primes_set: return False return True
def digits_factorials_chain(number: int) -> List[int]: chain = [number] while True: digits = number_to_digits(number) digits_factorials = map(factorial, digits) digits_factorials_sum = sum(digits_factorials) if digits_factorials_sum in chain: break number = digits_factorials_sum chain.append(number) return chain
def sub_string_divisible_numbers(*, digits: Iterable[int], slicers_by_divisors: Dict[int, slice] ) -> Iterable[int]: for digits in permutations(digits): number = digits_to_number(digits) digits = list(number_to_digits(number)) for divisor, slicer in slicers_by_divisors.items(): digits_slice = digits[slicer] sliced_number = digits_to_number(digits_slice) if sliced_number % divisor: break else: yield number
def is_digits_powers_sum(number: int) -> bool: return sum(digit**exponent for digit in number_to_digits(number)) == number
def is_digits_factorials_sum_candidate(number: int) -> bool: digits = tuple(number_to_digits(number)) zeros_count = digits.count(0) ones_count = digits.count(1) last_digit = digits[-1] return last_digit % 2 == (zeros_count + ones_count) % 2
def is_digits_factorials_sum(number: int) -> bool: digits_factorials_sum = sum(digits_factorials[digit] for digit in number_to_digits(number)) return digits_factorials_sum == number
yield 2 for index in count(1): yield 1 yield 2 * index yield 1 def convergent(index: int) -> Fraction: coefficients = list(islice(continued_fraction(), index)) # we are starting from the bottom to the top result = Fraction(coefficients.pop()) for coefficient in reversed(coefficients): result = coefficient + Fraction(1, result) return result assert [convergent(index) for index in range(1, 11)] == [ Fraction(2), Fraction(3), Fraction(8, 3), Fraction(11, 4), Fraction(19, 7), Fraction(87, 32), Fraction(106, 39), Fraction(193, 71), Fraction(1264, 465), Fraction(1457, 536) ] assert sum(number_to_digits(convergent(10).numerator)) == 17 assert sum(number_to_digits(convergent(100).numerator)) == 272
def number_to_sorted_digits_tuple(number: int) -> Tuple[int, ...]: return tuple(sorted(number_to_digits(number)))
def lychrel(number: int) -> bool: for _ in range(MAX_ITERATIONS_COUNT): number += digits_to_number(reversed(list(number_to_digits(number)))) if is_palindrome(str(number)): return False return True