1

I'm trying to iterate through multiple generators that are dynamically generated, in the order as specified in the user code.

I want to modify run() so that it can support n number of tasks, as opposed to three as of now. I tried using itertools.product() but I'm not sure how to call next() on my generators one at a time.

I think I will have to use recursion here but I'm not sure how to proceed. Any points are greatly appreciated.

class ImageSeries:
    def __init__(self):
        self.tasks = []

    def xy(self, position):
        print(f"xy: {position}")
        yield "xy"

    def z(self, position):
        print(f"z: {position}")
        yield "z"

    def exp(self, exposure):
        print(f"exp: {exposure}")
        yield "exposure"

    def xy_scan(self, positions):
        self._xy_task = lambda: (self.xy(pos) for pos in positions)
        self.tasks.append(self._xy_task)
    
    def z_scan(self, positions):
        self._z_task = lambda: (self.z(pos) for pos in positions)
        self.tasks.append(self._z_task)

    def exp_scan(self, exposures):
        self._exp_task = lambda: (self.exp(e) for e in exposures)
        self.tasks.append(self._exp_task)

    def run(self):
        for generator_0 in self.tasks[0]():
            next(generator_0)
            for generator_1 in self.tasks[1]():
                next(generator_1)
                for generator_2 in self.tasks[2]():
                    next(generator_2)

    def __repr__(self):
        return str(self.self.tasks)


if __name__ == "__main__":
    s = ImageSeries()
    positions = [[0, 0], [100, 100], [1000, 1000]]
    s.xy_scan(positions)
    s.exp_scan([50, 100, 150])
    s.z_scan([0, 100, 1000, 10000])
    s.run()

My desired output is:

xy: [0, 0]
exp: 50
z: 0
z: 100
z: 1000
z: 10000
exp: 100
z: 0
z: 100
z: 1000
z: 10000
exp: 150
z: 0
z: 100
z: 1000
z: 10000
xy: [100, 100]
exp: 50
z: 0
z: 100
z: 1000
z: 10000
exp: 100
z: 0
z: 100
z: 1000
z: 10000
exp: 150
z: 0
z: 100
z: 1000
z: 10000
xy: [1000, 1000]
exp: 50
z: 0
z: 100
z: 1000
z: 10000
exp: 100
z: 0
z: 100
z: 1000
z: 10000
exp: 150
z: 0
z: 100
z: 1000
z: 10000
pskeshu
  • 89
  • 9
  • 1
    in general you do it with recursion. I have several answers about "nested loops" but they are mostly in Common Lisp or Scheme or Prolog (or Haskell). there's a whole tag for it, too, [tag:recursive-backtracking]. then there's also [this](https://codereview.stackexchange.com/questions/224964/print-sums-of-all-subsets/224996#224996) and [this](https://codereview.stackexchange.com/questions/225018/general-algorithm-to-calculate-sums-of-all-subsets-of-a-given-sequence-of-number), in C++. – Will Ness Jul 18 '20 at 20:19
  • 1
    here's [an answer](https://stackoverflow.com/a/34562122/849891) with pseudocode creating *n* nested loops dynamically. see of any of this helps. – Will Ness Jul 18 '20 at 20:32

2 Answers2

1

How about modifying the for loop in run method as below,

def get_task(self):
    for task in self.tasks:
        yield task()

def loop_over(self, generator_obj):
    for generator in generator_obj:
        next(generator)
    self.loop_over(self.get_task())    

def run(self):
    self.loop_over(self.get_task())

This will ensure that all the n number of tasks are called.

Yogaraj
  • 191
  • 2
  • 14
1

Here is the recursive function where n should be start with 0

def run(self,n):
    for generator in self.tasks[n]():
        next(generator)
        m=n+1
        if m < len(self.tasks):
            self.run(m)
safiqul islam
  • 363
  • 2
  • 9