Search code examples
pythongeneratorconditional-operator

Python nested a generator inside a if else nested in a return is possible?


I try to create a shorter algorithms to guess if a number is a prime-number or not

So there is the algorithms that I want to short

def is_premier(n):
    i=2
    while i < n and n%i !=0:
        i+=1
    return i==n

And there is what I try to do:

def is_prime_v3(n):
    return ("Non Prime" if n%i==0 else "Prime" for i in range(2,n))

But I don't know if this generator is correct or there is a way to get the string ? My real interest is not the prime number algorith, I try to figure out if is it possible to get something with this following structure ( return a if condition else b for x in range(n); and collect the answer a or b)

Thanks for answers


Solution

  • You didn't manage to translate the first function correctly, no.

    • The function is_premier() returns a single boolean value, while is_prime_v3() returns a generator of strings.

    • The is_prime_v3() generator produces multiple "Prime" values for non-prime numbers, e.g. for 8, the test 8 % 3 == 0 is false, so "Prime" is generated:

      >>> list(is_prime_v3(8))
      ['Non Prime', 'Prime', 'Non Prime', 'Prime', 'Prime', 'Prime']
      

    Using a conditional expression is the wrong tool here. The first function stops early when a condition is met, while your second loop never stops early, and only produces different values each iteration.

    If you use a regular loop and print() calls instead of yielding, this is what is executed:

    for i in range(2, n):
        if n % i == 0:
            print("Non Prime")
        else:
            print("Prime")
    

    That loop also never stops when n % i == 0 is found.

    Now, it could have been your goal to do so, to produce Non Prime and Prime strings. However, it is easier if you used booleans instead, so True and False.

    Your first function could be described, in English, as doing this:

    • Start i at 2
    • as long as i is smaller than n and n % i != 0 is true, add one to i.
    • if i is equal to n, we have a prime number!

    You could also use a range() for that, and then it becomes:

    • Take i from the range 2 to n (not including n).
    • if ever n % i == 0 is true, this is not a prime number.
    • if we never found a value for i where n % i == 0, we have a prime number!

    In code that is:

    for i in range(2, n):
        if n % i == 0:
            return false
    return true
    

    For that kind of 'early exit' if a condition is met or not met, you can use the any() or all() functions. These work best with a generator, they test each value produced and return true or false early if the condition no longer holds.

    E.g. for the case where all values of i must not be a divisor, you can use:

    def is_prime_generator(n):
        return all(n % i != 0 for i in range(2, n))
    

    Finally, your own attempt, is_prime_v3(), could be made to do the same, if used as a utility function, where we don't require that all n % i != 0 tests are true, but that all strings are 'Prime':

    >>> all(s == 'Prime' for s in is_prime_v3(8))
    False
    >>> all(s == 'Prime' for s in is_prime_v3(7))
    True