0

I have this prime number generator, which needs to iterate through all existing prime numbers to determine if an examined value is prime, and then add it to the list:

primes = [2]
max_num = 10000

for num in range(3, max_num+1, 2):
  is_prime = True
  for prime in primes:
    if num % prime == 0:
      is_prime = False
  if is_prime == True:
    primes.append(num)

print(primes)

Is it possible to use a list comprehension to accomplish this? in some way such as this?

primes = [x for x in range(2, max_num+1) for y in primes if x % y != 0]

I tried running this code, and simply got a "primes is not defined" error.

Dylan Boyd
  • 19
  • 1
  • To be clear, by "current values", you mean the ones *that were previously calculated* by the same list comprehension? – Karl Knechtel Feb 16 '23 at 18:15
  • 2
    You can't iterate over a list _as its being built_, no. – John Gordon Feb 16 '23 at 18:15
  • @JohnGordon Sure you can. I've done it a few times. See for example the first link on my profile. – Kelly Bundy Feb 16 '23 at 18:16
  • Does this answer your question? [Is it possible to access current object while doing list/dict comprehension in Python?](https://stackoverflow.com/questions/21112814/is-it-possible-to-access-current-object-while-doing-list-dict-comprehension-in-p) – Woodford Feb 16 '23 at 18:19
  • 1
    @KellyBundy That is impressive, however I believe that the use of comprehensions should be to make code easier to understand and I don't feel like your nice solution invoking inspection of the garbage collector really makes it easier vs building an answer via a more traditional for loop. – JonSG Feb 16 '23 at 18:22
  • If you want a nitty gritty answer for the currently stated question in the header, you really should read @KellyBundy 's nice answer here: https://stackoverflow.com/questions/73753000/how-to-address-current-state-of-list-comprehension-in-its-if-condition/73755334#73755334 – JonSG Feb 16 '23 at 18:25
  • @KellyBundy Your example assigns the name name `L_unique` to the comprehension, and does not refer to _that name_ inside the comprehension itself. That is not the case in this question -- it (tries to) assign the name `primes` to the comprehension, and _also_ refers to that name inside the comprehension itself. (Perhaps my comment could have been a bit more specific, i.e. "You can't iterate over a list as it's being built, _in this specific way_".) – John Gordon Feb 16 '23 at 18:26
  • 1
    @JonSG I certainly agree. And I hope my first paragraph makes that clear. I just take issue with "You can't". – Kelly Bundy Feb 16 '23 at 18:26
  • @JohnGordon They try to access *the list*, that's the issue. Doesn't really matter that they tried to do that with some name. – Kelly Bundy Feb 16 '23 at 18:32
  • 1
    @JonSG Posted one here now, with a different technique to identify the list. I've had the idea to use a marker element for a while, but always thought of it as an *extra* element that I'd use to find the list and then remove before working on the actually wanted elements. But here, my `2` can stay, and it's quite natural. – Kelly Bundy Feb 16 '23 at 19:12

2 Answers2

1

Another list comprehension hack nobody should use. Just for fun. With a bonus hack about ints.

import gc

print([
    num
    for two in [(9**99 + 2) % 9**99]
    for nums in [[two], range(3, 100, 2)]
    for num in nums
    if num is two
       or all(num % prime
              for obj in gc.get_objects() if type(obj) is list and obj and obj[0] is two
              for prime in obj)
])

Output (Try it online!):

[2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47, 53, 59, 61, 67, 71, 73, 79, 83, 89, 97]

Lists get registered for cyclic garbage collection, so I use that to find the list object being built by the comprehension. How do I identify the list among all other lists? By starting it with a special 2. Not the usual 2, but a different int object with the value 2. That goes into the list directly. After that, I go through the odd numbers in the range. I find the list in the garbage collector by looking for my special 2. Once I have it, I go through it to check the current num for primality.

Optimized version, only searches the list once (Try it online!):

import gc

print([
    num
    for two in [(9**99 + 2) % 9**99]
    for nums in [[two], range(3, 100, 2)]
    for num in nums
    for primes in [() if num is two else primes or next(obj for obj in gc.get_objects() if type(obj) is list and obj and obj[0] is two)]
    if all(num % prime for prime in primes)
])

When num is my 2, I assign an empty dummy tuple to primes. When num is 3, I find and assign the list to primes. For all later numbers, I just re-assign primes to itself.

Kelly Bundy
  • 23,480
  • 7
  • 29
  • 65
-1

If you need solution which equal one line but it is not efficient by time

print([n for n in range(2, int(input())) if all(n % d for d in range(2,int(n**.5)+1))])
  • I suggest you measure how slow it is in comparison. You might be surprised. – Kelly Bundy Feb 17 '23 at 12:10
  • @KellyBundy You are right but You enter n>10^5 a bit slow This is code time-complexity = O(n*sqrt(n)) If you have significant number I suggest a sieve algorithm – Javohir Xoldorov Feb 17 '23 at 12:44
  • Sounds like you misunderstood me. I really suggest you measure. Let's say with N=10^5 (or N=10^6). (Calling it N because you use the name `n` for something different.) – Kelly Bundy Feb 17 '23 at 12:55