Im trying to create a a for loop using generator expressions and the zip function to display the first 8 tuples (a, b), where a is obtained using generator rnd_gen(1, -1), b is obtained using generator rnd_gen(2, -1), and 0
β€ a β€ b β€ 100. The idea is to filter out tuples for which a > b. My code seem creates the tuples for both generator variables, however the filtered variable just prints "[ ]". Is there anyway I can adjust this?
#π Writing a for loop using generator expressions and the zip function to display the first 8 tuples
116 messages Β· Page 1 of 1 (latest)
@analog crown
Remember to:
- Ask your Python question, not if you can ask or if there's an expert who can help.
- Show a code sample as text (rather than a screenshot) and the error message, if you've got one.
- Explain what you expect to happen and what actually happens.
:warning: Do not pip install anything that isn't related to your question, especially if asked to over DMs.
Closes after a period of inactivity, or when you send !close.
Its easier if you include code snippets rather than images.
!code
understood!
# COP 4045
# Homework 5
# Problem 2
# The defined Python random generator to serve as a basis for Problem 2
def rnd_gen(x0, n):
counter = 0
while n < 0 or counter < n:
x0 = (22695477 * x0 + 1) % (2**32)
yield x0
counter += 1
# Part A
# Creating a generator that creates an infinite sequence of tuples (a, b) where a and b are
# two random integers
def gen_rndtup(m):
rnd_generator = rnd_gen(1, -1)
while True:
a = next(rnd_generator) % m
b = next(rnd_generator) % m
if a <= b:
yield (a, b)
# Part B
# Usage of the itertools module and the lambda command
import itertools
filtered_tuples_b = itertools.islice(filter(lambda tup: sum(tup) >= 6, gen_rndtup(10)), 8)
print("Part B:")
print(list(filtered_tuples_b))
# Part C
print("\nPart C:")
gen_a = rnd_gen(1, -1) # Generator for a
gen_b = rnd_gen(2, -1) # Generator for b
filtered_tuples_c = [(a, b) for a, b in itertools.islice(zip(gen_a, gen_b), 8) if a <= b <= 100]
print("Filtered tuples:", filtered_tuples_c)
# Part D
print("\nPart D:")
filtered_numbers = itertools.islice(filter(lambda x: x % 13 == 0, map(lambda x: x % 101, rnd_gen(1,-1))), 10)
print(list(filtered_numbers))
# Part E
print("\nPart E:")
import functools # Importing the functools module
filtered_tuples_e = itertools.islice(filter(lambda tup: sum(tup) >= 5, gen_rndtup(10)), 10)
sum_of_tuples = functools.reduce(lambda x, y: (x[0] + y[0], x[1] + y[1]), filtered_tuples_e)
print(sum_of_tuples)
this pertains to part c
is it supposed to be full of stuff?
an empty list isn't necessarily a wrong answer
if it's supposed to have stuff in it, make sure that you have read the condition properly
I think it's supposed to contain 8 tuples.
why would they be asked to filter if that was the case?
hmm I see what you mean
you actually skip the ones for which the condition is false
which means you need to put the filtering inside of the islice?
that does make it take quite a while btw
yeah there needs to be 8 tuples, but I can try your suggestion and see if it works
I didn't generate a single tuple since I said this
(I stopped it now)
can you confirm the condition?
Take two random numbers 0..2**32, how likely is it that both are below 100 and that the first is smaller then the second? About 0.00000000000003% chance.
well they aren't actually random, but I doubt that makes a massive difference
no idea.
it might actually be impossible for that to happen with specific seeds together, idk
it took me like 1 minute to get just one number <= 100 with rnd_gen(1, -1) in a loop
ok nvm the long time was because I was building a set of the numbers seen
more like 15 to 20 seconds
The 50997500th number is 85.
def rnd_gen(x0, n):
counter = 0
while n < 0 or counter < n:
x0 = (22695477 * x0 + 1) % (2**32)
yield x0
counter += 1
s = set()
for i, x in enumerate(rnd_gen(1, -1)):
if x <= 100:
if x in s:
break
s.add(x)
print(f"iteration {i}: {x}")
print(f"{len(s) = }")
print("Repeat found")
this is what I'm cooking rn
I should've added a print for what the repeat number is...
I'm gonna rewrite the random generation specifically for the infinite case to save some time and make some changes to the loop code I wrote
nothing seems to work I've tried adjusting it as much as I can be and it keeps printing []
that is because it takes fucking forever, if there is even a possible answer
are you certain that the condition 0 <= a <= b <= 100 is correct by the instructions?
if it takes forever it shouldn't print [].
wait sorry you said it is printing...
I realized before jenna said but typing = paing
this is the prompt
I think the task is to write code, not to execute it.
perhaps
if you are actually able to run the code in a reasonable time to say "oh here's the output guys", you've done it wrong
I hope that is the case however this is at the end of the question
skull
well, have fun leaving your python script running overnight (or longer, who knows)
all other parts work completely perfect idk why part c is giving me a problem
you need to islice after filtering, not before
you forgot to multiply by 100 when making it a percentage
only 10 more numbers less than or equal to 100 left before I get a repeat (for rnd_gen(1, -1))
so looks like it visits every number (which I probably could've googled)
!e py from fractions import Fraction print(f"{Fraction(100, 2**32) ** 2 / 2:.15%}")
@tulip halo :white_check_mark: Your 3.12 eval job has completed with return code 0.
0.000000000000027%
actually hol-up, I don't even need to run the second rnd_gen through
because all numbers are used, can just inspect starting at 2 and look at the deltas
Here's the data as JSON
https://paste.pythondiscord.com/IDJA
~~sorry wait ~~
obviously there are seeds for which the condition can be true, and we can enumerate all of them using that data
I think I want to chance the data to show 0 as the 0th iteration tho
ok I checked, with inputs
gen_a = rnd_gen(1, -1) # Generator for a
gen_b = rnd_gen(2, -1) # Generator for b
you cannot satisfy the condition
simply because <= 100 never aligns
now I will check all combinations of seeds <= 100 because why not
so you can stop once the tuple (1,2) is encountered
what
i mean like a itertools.takewhile(lambda t: t != (1, 2), zip(rnd_gen(1, -1), rnd_gen(2, -1))
so it stops searching once the initial seeds come up.
I don't get it
the initial seed comes up every 2**32 iterations
ah
btw I screwed up how I tested this, so I'm working on fixing it
ok fixed now
import json
with open("seq.json") as f:
data = {int(k): v for k, v in json.load(f).items()}
reverse_data = {v: k for k, v in data.items()}
def from_n(n: int):
offset = reverse_data[n]
return dict(sorted(((k + 2**32 - offset) % 2**32, v) for k, v in data.items()))
def compare(x, y):
return [a == b for a, b in zip(from_n(1), from_n(2))]
print(compare(1, 2))
I see what you meant now
they only line up on the last iteration for that input
ah, i didn't think of that.
so we can say that the output will be
[(1, 2), (1, 2), (1, 2), (1, 2), (1, 2), (1, 2), (1, 2), (1, 2)]
nice
actually i'm not sure if they really get back to the initial seeds.
they must
I tested for input 1 and it goes through all possible values 0 <= x < 2**32
also the amount of unique values is finite, so at least they would have to settle into some period
but because 1 goes through all numbers, then every x0 goes through all numbers for OPs function
now to see if any can have possibly have multiple unique pairs, or only repeats the ending pair
ah, indeed.
looks like the maximum that can overlap is one, which is the initial pair
import itertools
import json
with open("seq.json") as f:
data = {int(k): v for k, v in json.load(f).items()}
reverse_data = {v: k for k, v in data.items()}
def from_n(n: int):
offset = reverse_data[n]
return dict(sorted(((k + 2**32 - offset) % 2**32, v) for k, v in data.items()))
def from_n_only_iteration(n: int):
offset = reverse_data[n]
return sorted((k + 2**32 - offset) % 2**32 for k in data)
def compare(x: int, y: int):
return [a == b for a, b in zip(from_n_only_iteration(1), from_n_only_iteration(2))]
def delta(n: int):
return [b - a for a, b in itertools.pairwise(from_n(n))]
one = []
many = {}
for a, b in itertools.combinations(range(101), 2):
c = compare(a, b)
s = sum(c)
if s == 1:
one.append((a, b))
elif s > 1:
many[(a, b)] = c
print(one)
print()
print()
print(many)
from_n_only_iteration makes a list of indices offset to start at the index of n
compare makes a list of equal indices after offsetting
and honestly I didn't even need to make the one list because we know that all inputs a, b will come back to themselves after 2**32 iterations
is there any way you might have misunderstood and you're actually supposed to reduce the numbers mod 101 so they are forced in the range [0,100]
oh wait, I forgot about a == b
something like this
def answer_c(a: int, b: int) -> list[tuple[int, int]]:
if a < b:
return [(a, b)] * 8
if a == b:
return [
(x, x)
for x in itertools.islice((r for r in rnd_gen(a, -1) if 0 <= r <= 100), 8)
]
return []
@tulip halo just gotta pray that a != b π
hm. yes in that case the return value is still not correct. it needs to be an infinite loop.
so maybe while True: pass instead of return [].
the task description is here: #1225231904702337174 message
but the definition of rnd_gen is missing.
or raise an error idk
an actual infinite loop I don't like
i find the loop+generator+zip requirement more concerning. that would be something likepy for a, b in islice(((a, b) for a, b in zip(rnd_gen(1, -1), rnd_gen(2, -1)) if 0 <= a <= b <= 100), 8): print(a, b)
my brain recognize this as a javascript π
it doesn't look anything like JS
replied to the wrong message. I mean the below with the list comp
I mean... still doesn't look like JS
rnd_gen has already been defined for reference. I believe I posted that segment at the beginning of the discussion
yes, it looks slightly like es5 because they adopted the array comprehension. but they have been removed again in es6.
ES6 came out in 2015... although looks like comprehensions will again come to ES7, but better than they originally were
Ah.. Right, I totally forgot that Babel even exists. I'm glad I switched to python long ago. 
This help channel has been closed and it's no longer possible to send messages here. If your question wasn't answered, feel free to create a new post in #1035199133436354600. To maximize your chances of getting a response, check out this guide on asking good questions.