Python Python Collections (2016, retired 2019) Tuples Combo

combo function tuple

I am stuck as to how to not repeat i1 multiple times. my code is returning: [(1, 'a'), (1, 'b'), (1, 'c'), (2, 'a'), (2, 'b'), (2, 'c'), (3, 'a'), (3, 'b'), (3, 'c')]

How do I fix this? i'm just really stuck
# combo([1, 2, 3], 'abc')
# Output:
# [(1, 'a'), (2, 'b'), (3, 'c')]

def combo(itr1, itr2):
    lst = []
    iter1 = list(itr1)
    iter2 = list(itr2)
    for i1 in iter1:
        for i2 in iter2:
            lst.append((i1, i2))
    return lst

You only have to iterate through the list one time and use the index for both iterations.

for i in range(0, len(itr1)):
          lst.append((itr1[i], itr[i]))


2 Answers

Jeff Muday
Jeff Muday
Treehouse Moderator 25,042 Points

It looks like you understand the concept of nested loops, let's build on that. There are MANY ways to do this, but I am going to show you a cool "trick".

Something that you should learn to use is "enumerate()" which is a cool generator function that returns an index and item tuples.

A simple example of how it would work...

(Python 3.6.5 |Anaconda, Inc.| (default, Mar 29 2018, 13:32:41) [MSC v.1900 64 bit (AMD64)] on win32
Type "help", "copyright", "credits" or "license" for more information.
>>> days = ['Monday','Tuesday','Wednesday','Thursday','Friday']
>>> for i, item in enumerate(days):
...     print(i, item)
0 Monday
1 Tuesday
2 Wednesday
3 Thursday
4 Friday
>>> # this would also work on a string
>>> for i, item in enumerate(s):
...     print(i, item)
0 A
1 B
2 C
3 D
4 E
5 F
6 G
7 H

... stuff deleted ...
18 S
19 T
20 U
21 V
22 W
23 X
24 Y
25 Z

SPOILER ALERT -- don't read any further if you want to solve it yourself.

Now, we can take this idea and combine two iterables into matched combo tuples.

>>> def combo(itr1, itr2):
...     lst = []
...     for i, item in enumerate(itr1):
...         lst.append( (itr1[i], itr2[i]) )
...     return lst
>>> combo([1,2,3],'abc')
[(1, 'a'), (2, 'b'), (3, 'c')]

Thank you for the explanation. i was thinking of the problem from a Java perspective. do we absolutely need the "item" variable in the for loop? is that because of the enumerate function? thanks

Jeff Muday
Jeff Muday
Treehouse Moderator 25,042 Points

You will discover that there are all kinds of ways to accomplish your goals in Python. In this case, it is a little difficult to accomplish without an index variable, but entirely possible.

One way to do this is to treat the iterables like a reverse stack.

  1. convert iterables (itr1, itr2) to lists (list1 and list2) reason: if either one or the other iterable is a string, it won't have "pop()" so converting to a list solves it.
  2. while list1 is non empty, pop first element of list1 and list2 and create a tuple which is appended to our result. -- note that -- list1 and list2 are reduced in size each time we pop off an element
  3. finally, return the lst we built
def combo(itr1, itr2):
    lst = []
    # since either one of these iterables could be a string, we need a list conversion
    list1 = list(itr1)
    list2 = list(itr2)
    while list1:
        # we use a pop() method from the list to remove the first element.
        lst.append( (list1.pop(0), list2.pop(0) )
    return lst

That's awesome! I didn't even think of that. Thanks