5 Best Ways to Check if a Number is a Perfect Number in Python

πŸ’‘ Problem Formulation: We aim to determine if a given integer is a perfect number. In number theory, a perfect number is a positive integer that is equal to the sum of its proper divisors, excluding the number itself. For instance, 28 is a perfect number because its divisors (1, 2, 4, 7, 14) sum up to 28.

Method 1: Using a Loop

This method involves iterating through all possible divisors of the input number and accumulating their sum. If the sum of divisors matches the original number, it is perfect.

β™₯️ Info: Are you AI curious but you still have to create real impactful projects? Join our official AI builder club on Skool (only $5): SHIP! - One Project Per Month

Here’s an example:

def is_perfect_number(num):
    sum_of_divisors = 0
    for i in range(1, num):
        if num % i == 0:
            sum_of_divisors += i
    return sum_of_divisors == num

print(is_perfect_number(28))

Output: True

This function is_perfect_number iterates from 1 up to the number (exclusive) and checks if each integer is a divisor. If it is, it adds that number to sum_of_divisors. After completion, it checks if the sum of these divisors equals to the original number to determine if it’s perfect.

Method 2: Using List Comprehension

Python’s list comprehension feature can be used for a cleaner approach to gather all divisors and calculate their sum in a single line of code.

Here’s an example:

def is_perfect_number(num):
    return sum([i for i in range(1, num) if num % i == 0]) == num

print(is_perfect_number(28))

Output: True

In this simplified approach, list comprehension is used to create a list of all divisors of num, which is then passed to the sum function. The result is compared directly to the initial number to check for perfection.

Method 3: Utilizing the sqrt Function

We can improve efficiency by iterating only up to the square root of the number because a divisor larger than the square root would have a corresponding divisor smaller than the square root.

Here’s an example:

import math

def is_perfect_number(num):
    sum_of_divisors = 1
    for i in range(2, int(math.sqrt(num)) + 1):
        if num % i == 0:
            sum_of_divisors += i + num // i
    return sum_of_divisors == num

print(is_perfect_number(28))

Output: True

In this code snippet, we start the sum at 1, since 1 is a divisor of every number. By iterating up to the square root, we avoid unnecessary checks and, when a divisor is found, we add both the divisor and its corresponding pair to the sum. Eventually, we compare this sum to the input number.

Method 4: Using a Generator Expression

A generator expression allows us to evaluate the sum without creating an intermediate list, thus being more memory efficient.

Here’s an example:

def is_perfect_number(num):
    return sum(i for i in range(1, num) if num % i == 0) == num

print(is_perfect_number(28))

Output: True

Here, we have replaced the list comprehension with a generator expression. This means we sum up the divisors lazily, which can be useful for memory optimization especially with larger numbers.

Bonus One-Liner Method 5: Using sum with Generator Expression

For the enthusiasts of one-liners, we present this concise expression that does it all at once.

Here’s an example:

print(sum(i for i in range(1, 28) if 28 % i == 0) == 28)

Output: True

This one-liner checks the perfection of the number 28 directly within the print statement using a generator expression. It is neat but sacrifices readability for brevity.

Summary/Discussion

  • Method 1: Loop. Straightforward implementation. Not the most efficient for large numbers due to iteration over all integers less than the number.
  • Method 2: List Comprehension. More Pythonic and concise. Still, it’s not efficient for large numbers due to the same iteration issue.
  • Method 3: Utilizing sqrt. It’s more efficient as it reduces the iterations required. However, it involves slightly more complex logic.
  • Method 4: Generator Expression. Memory efficiency as it avoids creating an intermediate list. Suitable for large numbers but may not provide a significant speed advantage.
  • Method 5: One-Liner using Generator Expression. Extremely concise. Best used for quick checks or small scripts. Might be hard to read and understand for beginners.