field = [0] * 100
field[0] = 1
print(2)
for i, state in enumerate(field):
if state: continue
print(i * 2 + 1)
field[i] = 1
for i in range(2 * i * (i + 1), len(field), i * 2 + 1):
field[i] = 2
Post your explanations, preferably spoiler tagged so others can have fun with this too.
Is this an elegant piece of code, or an abomination?
# They have a lot of spam at this buffet
buffet = ['eggs'] + (['spam'] * 100)
print(2)
for plate, meal in enumerate(buffet):
if meal == 'eggs': continue
print(plate * 2 + 1)
buffet[plate] = 'eggs'
for tray in range(2 * plate * (plate + 1), len(buffet), plate * 2 + 1):
buffet[tray] = 'eggs'
In all seriousness, this is a fun experiment in lazy iteration. Hereâs an even lazier version:
field = [1] + ([0] * 100)
print(2)
for i, _ in filter(lambda x: not x[1], enumerate(field)):
print(i * 2 + 1)
delta = i, len(field), 2*i + 1
field[slice(*delta)] = (1 for _ in range(*delta))
An even more ridiculous code golfed version (I abandoned the optimized i*2 * (i + 1)start index for brevity)
def prime_madness(n: int=100):
yield 2
for i, _ in filter(lambda x: not x[1], enumerate(f := [1]+([0]*(n-1)))):
yield (g := i*2+1)
f[slice(i, n, g)] = range(i, n, g)
The only part Iâm having trouble with is the 2*i*(i+1) part
Obviously this is a fun way of doing a prime sieve. I think my edited examples as I played with it should show that. The lazy iteration over the list using enumerate is a fun trick to modify the sieve in place using the index as p , something that is clear in my final example since state ends up getting totally factored out since itâs handled by the filter case.
The eggs and spam joke was just meant to point out that the values assigned to the field mean nothing since theyâre just flags for telling if a specific index has been checked.
Finally, this sent me down a cursed code golf rabbit hole that ended with this one liner that gets the first 100 primes (not a proper sieve, but boy is it an abomination)
r=[*range(2,98)];[print(i) for i in r if all(i%j for j in r[:i-2])]
@Rosuav Is this the part Iâm missing? I did notice that this index converges really quickly (i==5). The fact that you can index a range that starts at >len(seq) is definitely a fun quirk. Means you finish filtering really early on and the inner loop only runs a few times.
The code I presented produces output which is, in the scheme of things, not particularly special or unusual. Itâs a very famous sequence. But the code is doing something slightly different from the simple and most obvious way of finding that sequence, and thatâs part of whatâs going on with the 2*i+1 expression.
Itâs interesting how much of this example code can be removed while not altering the output really. The Sieve of Eratosthenes will mark a number from any factor, but your example avoids almost all of that double counting.
Not an Euler sieve. Storing only odd ints is common in Eratosthenes, and so is that after finding a prime p, donât bother âcrossing outâ anything smaller than p^2 (any composite less than that must have already been crossed off - must have a prime factor less than p). Euler is more aggressive than just that, taking pains to cross out each composite exactly once (by, and only by, its smallest prime factor).
So far, noone talked about the resulting field. If it were just an internal tool to achieve the output, the line field[i] = 1 wouldnât be there and the final line would also assign 1 instead of 2. So whatâs up with that?
Not true :-). Iâve known that since it came up in some regex challenge a long time ago. Canât find it now, maybe itâs gone. I think the challenges were in the style of this, i.e., with âMatch theseâ and âDonât match theseâ.
Since the inner loop is indexed at i*2*(i+1) instead of i , without the field[i] = 1 youâd miss the first step in the sieve. The actual value doesnât matter, but if you check the contents of field youâll see exactly where each number was crossed from (main loop or inner loop).
Since the field is Boolean, you can use any truthy/falsely object for your flag (0 or non-zero). Which is why my first snippet just changed the condition to == âeggs.
filter(âŚ, enumerate(âŚ)) donât do anything with the underlying iterable until next is called, so the filter is modified by the state changes inside the loop. Itâs really just a way to drop the condition. You do still need to initialize the field.