1

I need to make a "generator function" which will take 2 lists and concatenate numbres from two lists by indices into a tuple. For example:

l1 = [3, 2, 1]
l2 = [4, 3, 2]

The result of the first iteration will be (3, 4) The result of the second iteration will be (2, 3) And the third (1, 2) And also, one of lists may have more numbers than the other one. In that case I need to write condition "if one of the lists ended while iterating, then no further iterations are performed." (using try, except)

I know, that generator functions use yield instead of return, but I have no idea how to write this fuction... I did this

def generate_something(l1, l2):
    l3 = tuple(tuple(x) for x in zip(l1, l2))
    return l3

output is

((3, 4), (2, 3), (1, 2))

It works, but this is not geterator function, there is no yield, there is no first-,second-,etc- iterations. I hope you can help me...

Ruslan
  • 43
  • 6

3 Answers3

2

May be this help for you:

def generate_something_2(l1, l2):
    # if one of the lists ended while iterating, then no further iterations are performed.
    # For this get minimal len of list
    min_i = len(l1) if len(l1) < len(l2) else len(l2)
    for i in range(0,min_i):
        yield (l1[i], l2[i])

l1 = [3, 2, 1, 1]
l2 = [4, 3, 2]

l3 = tuple(generate_something_2(l1, l2))
# Result: ((3, 4), (2, 3), (1, 2))
print(l3)
  • yes, it works too. But don't you know how can I print at first the first iteration, then the second iteration, and then the third one? I did ```l3 = tuple(next(generate_something_2(l1, l2)))``` in your code. But it prints only the first iteration when i write print(l3) – Ruslan Nov 15 '20 at 13:59
  • I got it. I did this ```l3 = generate_something_2([3, 2, 1, 1], [4, 3, 2]) print(next(l3)) print(next(l3)) print(next(l3)) ``` – Ruslan Nov 15 '20 at 14:07
1

you can create your own generator:

def iterate_lists(l1,l2):
   for i,item in enumerate(l1):
       yield l1[i],l2[i]

or as a variable by generator comprehension:

iterate_lists = (li[i],l2[i] for i,item in enumerate(l1))

about if the lengthes arent equal its not clear to me what exactly you want to do, without the message you can just go on the smaller list... just change the for i,item in enumerate(l1) with for i in range(min((len(l1),len(l2)))

adir abargil
  • 5,495
  • 3
  • 19
  • 29
  • yes, i tried this too, but when i write ```yield``` the output is `````` which is not what the task asks – Ruslan Nov 15 '20 at 13:41
  • 1
    because it is a generator, what excactly do you want to print? you can just use the function `next()` on the generator to iterate over it... – adir abargil Nov 15 '20 at 13:45
1

Use a while loop and keep track of the index position, when a IndexError is raised you've hit the end of the shortest list and stop:

def generate_something(l1, l2):
    idx = 0
    while True:
        try:
            yield l1[idx], l2[idx]
            idx += 1
        except IndexError:
            break


l1 = [3, 2, 1]
l2 = [4, 3, 2]

g = generate_something(l1, l2)
print(list(g))

Output:

[(3, 4), (2, 3), (1, 2)]
Terry Spotts
  • 3,527
  • 1
  • 8
  • 21
  • if i do ```print(next(g))``` 4 times instead of ```print(list(g))```, than there is an Error ```StopIteration```, do you know how to fix this Error? I tried to write ```except StopIteration``` but it doesn't work – Ruslan Nov 15 '20 at 15:22
  • that `StopIteration` lets the caller know the generator is exhausted. `list(g)` handles this implicitly, you would need to write some code outside of `generate_something()` when calling `next(g)` multiple times. – Terry Spotts Nov 15 '20 at 15:35