To answer the question: to turn a function into a generator function, all you have to do is yield
something. You might do it like this:
def convert(data):
for index in range(len(data)):
...
yield data
Then, you can iterate over the output like this:
iter_converted_datas = convert(data)
for _, converted in zip(range(256), iter_converted_datas):
print(len(converted))
I also would suggest some improvements to this code. The first thing that jumps out at me, is to get rid of all those elif statements.
One helpful thing for this might be to supply a dictionary argument to your generator function that tells it how to convert the data values (the first one is a special case since it also appends).
Here is what that dict might look like:
replacement_dict = {
0: 6,
1: 0,
2: 1,
3: 2,
4: 3,
5: 4,
6: 5,
7: 6,
8: 7,
}
By the way: replacing a series of elif statements with a dictionary is a pretty typical thing to do in python. It isn't always appropriate, but it often works well.
Now you can write your generator like this:
def convert(data, replacement_dict):
for index in range(len(data)):
if index==0:
lst.append(8)
data[index] = replacement_dict[index]
yield data
And use it like this:
iter_converted_datas = convert(data, replacement_dict)
for _, converted in enumerate(iter_converted_datas):
print(len(converted))
But we haven't yet addressed the underlying memory problem.
For that, we need to step back a second: the reason your memory is filling up is you have created a routine that grows very large very fast. And if you were to keep going beyond 256 iterations, the list would get longer without end.
If you want to compute the Xth output for some member of the list without storing the entire list into memory, you have to change things around quite a bit.
My suggestion on how you might get started: create a function to get the Xth iteration for any starting input value.
Here is a generator that just produces outputs based on the replacement dict. Depending on the contents of the replacement dict, this could be infinite, or it might have an end (in which case it would raise a KeyError
). In your case, it is infinite.
def process_replacements(value, replacement_dict):
while True:
yield (value := replacement_dict[value])
Next we can write our function to process the Xth iteration for a starting value:
def process_xth(value, xth, replacement_dict):
# emit the xth value from the original value
for _, value in zip(range(xth), process_replacements(value, replacement_dict)):
pass
return value
Now you can process the Xth iteration for any value in your starting data list:
index = 0
xth = 256
process_xth(data[index], xth, data, replacement_dict)
However, we have not appended 8 to the data
list anytime we encounter the 0 value. We could do this, but as you have discovered, eventually the list of 8s will get too big. Instead, what we need to do is keep COUNT of how many 8s we have added to the end.
So I suggest adding a zero_tracker
function to increment the count:
def zero_tracker():
global eights_count
eights_count += 1
Now you can call that function in the generator every time a zero is encountered, but resetting the global eights_count
to zero at the start of the iteration:
def process_replacements(value, replacement_dict):
global eights_count
eights_count = 0
while True:
if value == 0:
zero_tracker()
yield (value := replacement_dict[value])
Now, for any Xth iteration you perform at some point in the list, you can know how many 8s were appended at the end, and when they were added.
But unfortunately simply counting the 8s isn't enough to get the final sequence; you also have to keep track of WHEN (ie, which iteration) they were added to the sequence, so you can know how deeply to iterate them. You could store this in memory pretty efficiently by keeping track of each iteration in a dictionary; that dictionary would look like this:
eights_dict = {
# iteration: count of 8s
}
And of course you can also calculate what each of these 8s will become at any arbitrary depth:
depth = 1
process_xth(8, depth, data, replacement_dict)
Once you know how many 8s there are added for every iteration given some finite number of Xth iterations, you can construct the final sequence by just yielding the correct value the right number of times over and over again, in a generator, without storing anything. I leave it to you to figure out how to construct your eights_dict
and do this final part. :)