4

as a personal exercise I am trying to create my own little zip() function that takes two lists and puts the items into a list of tuples. In other words if these are my list:

fr = [6,5,4]
tr = [7,8,9]

I would expect this:

[(6,7), (5,8), (4,9)]

Here is my code:

def zippy(x, y):
    zipper = []
    for i in x :
        for g in y:
            t = (i,g)
        zipper.append(t)

What I get is: [(6, 9), (5, 9), (4, 9)], but when I define the lists inside of the function, it works as intended. Any help is appreciated.

4
  • You assign to t three times before you append it, meaning that the first entry in your list of tuples will be the very last value in y. Commented Jan 20, 2016 at 6:00
  • Thanks! Do you know why it works if the lists are contained in the function? That is making me scratch my head. Commented Jan 20, 2016 at 6:04
  • I was unable to reproduce what you experienced, could you post the code you used? I've defined the lists inside of the function rather than out and it still returns the wrong results. Commented Jan 20, 2016 at 6:08
  • Strange, you're right. Hmm, I can't step back far enough with Eclipse to find out what I was doing! Thanks again. I get a little better everyday. Commented Jan 20, 2016 at 6:14

7 Answers 7

3

Use indexes to access same-indexes items:

def zippy(x, y):
    zipper = []
    for i in range(len(x)):
        zipper.append((x[i], y[i]))
    return zipper

using list comprehension:

def zippy(x, y):
    return [(x[i], y[i]) for i in range(len(x))]

>>> fr = [6,5,4]
>>> tr = [7,8,9]
>>> zippy(fr, tr)
[(6, 7), (5, 8), (4, 9)]
Sign up to request clarification or add additional context in comments.

3 Comments

This is great, but do you know why m original code works if the lists are defined in the function?
@SeaWolf, The reason it does not work: zipper.append(t) is called after the inner loop. t[1] will always refers the last item of y. I don't think it works even though the lists are defined in the function. Could you provide the code that works (which defines lists in the function)?
I can't, I ran out of "undues" in Eclipse to find out what little tweaked was producing that. Thanks, for the thorough answer.
3

Please consider that if you have two lists of different length your zip should stop when the shortest sequence ends. Here is an example of how to do it:

def zippy(x, y):
    iter1 = iter(x)
    iter2 = iter(y)
    while True:
        try:
            yield next(iter1), next(iter2)
        except StopIteration:
            return

or

def zippy(x, y):
    iter1 = iter(x)
    iter2 = iter(y)
    for _ in range(min(len(x), len(y))):
        yield next(iter1), next(iter2)

Also notice that standard zip function returns (generator) and not a list of data! That means if you need to get data from your result you have to convert your zip result to list:

result = zippy(fr, tr)
print(list(result))

or call iterator on it

next(result)

Comments

2

I would suggest using range() to cycle through each index of the array. Then, put them in a tuple and append them to the array.

def zippy(x, y):
    zipper = []
    for i in range(len(x)) :
        zipper.append((x[i],y[i]))
    return zipper

For more info on range(), go here.

Comments

1

You need to iterate both arrays at the same time to get the same indexes from both arrays

 def zippy(x, y):
        zipper = []
        for i,g in zip(x,y):
            t = (i,g)
            zipper.append(t)
        print(zipper)

Output

[(6, 7), (5, 8), (4, 9)]

Comments

1
# A zip() is a kind of map()!
def zippy(a, b):
  return map(lambda (i, a): (a, b[i]), enumerate(a))

Comments

1

None of the prior answers support a variable number of iterables as are supported by Python's native zip function. Consider the following generalized implementation which does support it. It also does not rely on map.

def zipper(*iterables):
    # Ref: https://stackoverflow.com/a/77297966
    if not iterables:
        return (_ for _ in ())  # Without this the function runs forever.

    iterables = [iter(it) for it in iterables]
    try:
        while True:
            yield tuple([next(it) for it in iterables])
    except StopIteration:
        return

Usage example:

> zipper(range(11, 15), range(20, 30))
<generator object zipper at 0x7fb6671a6420>

> list(_)
[(11, 20), (12, 21), (13, 22), (14, 23)]

The example in the question also works fine.

Comments

0

Assuming that you want to make sure the lists are equal length before operation, you can utilize Python's assert statement in the function along with a list comprehension.

def zippy(x,y):
    assert len(x) == len(y), 'Lists must be equal length to each other'

    return [(i,j) for i,j in zip(x,y)]

The assert statement makes sure that the arguments x and y are equal length. If they aren't equal, then the function won't run and will return an AssertionError.

Then, the functions returns a list created from a list comprehension. The list comprehension creates a tuple for each index of the lists, in which the indices are paired when the zip() function is called on the lists.

If you aren't worried about iterating the lists with generators like other solutions propose, then this solution will serve well.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.