2

I have the following problem. I have to implement a function as a generator, which expects any number of iterables. It can be assumed that the iterables issue their elements each time in the same order. The function should return all elements that are in the same place in all iterables (view asserts):

def intersect(*iterables, **kwiterables):
    for obj in iterables:
        #need help here :)
        #already tried something like:
        # obj = (var for var in obj if var in iterables)
    yield obj

#asserts:
assert list(intersect((1,2,3))) == [1,2,3]
assert list(intersect((1,2,3), (1,"x",3))) == [1,3]
assert list(intersect([1,1,1,1,1,1,1,1,1], [1,2,1,2,1,2,1,2,1,2], k = [3,3,1,3,3,1,3,3,1,3,3,1])) == [1,1]

Would be glad about a solution of my problem with explanation.

mkrieger1
  • 19,194
  • 5
  • 54
  • 65
lukasschr
  • 25
  • 4
  • I would recommend using `next()` for each iterable (only once) per function call (and retaining the same iterable) – lucidbrot Dec 06 '19 at 12:59
  • `iterables` is a list of iterables. Therefore, your `for obj in iterables` doesn't compare the elements between different lists, `obj` is always one of the lists! E.g. for `intersect((1,2,3), (1,"x",3))`, your `obj` is `(1,2,3)` during first iteration and `(1,"x",3)` during second. – h4z3 Dec 06 '19 at 13:00
  • Does this answer your question? [What is the best way to iterate over multiple lists at once?](https://stackoverflow.com/questions/10080379/what-is-the-best-way-to-iterate-over-multiple-lists-at-once) – mkrieger1 Dec 06 '19 at 13:02

1 Answers1

5

You can use the zip built-in function to iterate over all the iterables in parallel.

For example, zip(it_a, it_b, it_c) iterates over triples (a, b, c), where a comes from it_a, b comes from it_b, and c comes it_c. The first triple contains the first elements of the iterables, the second contains the second ones, and so on. You can combine this with the * syntax for passing an arbitrary number of arguments to get zip(*iterables) which prouces n-tuples with all the elements. (You can further pass both *iterables and *kwiterables.values() to combine the iterables and kwiterables.) Finally, once you get the "row" of values, you just need to check that all elements of the row are equal.

The final result can look like this (which passes your tests):

def intersect(*iterables, **kwiterables):
    for objs in zip(*iterables, *kwiterables.values()):
        first = objs[0]
        if all(o == first for o in objs[1:]):
            yield first
user4815162342
  • 141,790
  • 18
  • 296
  • 355