1

I'm trying to understand the difference between zip() and zip(*).

From what I understand, zip() can be used to combine two lists, such that elements with a shared index are together. Such as in these examples:

dict_list = {'First Name': ['Tom', 'Ann', 'Ben'],
             'Last Name': ['Haverford', 'Perkins', 'Wyatt'],
             'Age': [33, 42, 44],
             'Occupation': ['Administrator', 'Nurse', 'Auditor']}

for first_name, last_name, age, occupation in zip(dict_list['First Name'], dict_list['Last Name'], dict_list['Age'], dict_list['Occupation']):
             print(first_name, last_name, age, occupation)

#result    

Tom Haverford 33 Administrator
Ann Perkins 42 Nurse
Ben Wyatt 44 Auditor

So why does it seem to me that sometimes, zip(*) behaves this way? For example:

for t in (zip(*dict_list.values())):
    print(t)
#result    

('Tom', 'Haverford', 33, 'Administrator')
('Ann', 'Perkins', 42, 'Nurse')
('Ben', 'Wyatt', 44, 'Auditor')

Since my dict_list.values() are lists, it seems like zip(*) placed all elements with shared indexes in the same tuple. Which is not that much different from the first code, in which I used zip() in a for loop with dict keys passed into it and with corresponding looping variables

How are zip() and zip(*) behaving in this case?

Marielle Dado
  • 147
  • 1
  • 11
  • 1
    `func(*lst)` is the same as `func(lst[0], lst[1] ... , lst[-1])` – Rocky Li Mar 13 '19 at 17:36
  • 1
    You just wrote two different ways to do the same thing. Voting to close as unclear what you're asking. – wim Mar 13 '19 at 17:36
  • `zip(*)` does unpacking before the real zip operation, whereas `zip()` is directly zip. – Austin Mar 13 '19 at 17:38
  • @wim Somehow I came across the same results when using `zip()` and `zip(*)` when I'm expecting them to behave differently. And I'm wondering what the mechanisms are that that led to the same result, when they're supposed to be opposites. – Marielle Dado Mar 13 '19 at 17:40

1 Answers1

2
>>> dict_list.values()
[['Tom', 'Ann', 'Ben'], ['Haverford', 'Perkins', 'Wyatt'], [33, 42, 44], ['Administrator', 'Nurse', 'Auditor']]

This returns a list containing the four sub-lists.

zip(*dict_list.values())

And this unpacks that list and passes each of the elements as separate arguments to zip(). That's what the * unpacking operator does: if you call zip(*l) with a list l that contains four elements, it calls zip() with those four arguments.

Compare it to the first snippet you wrote, which passes the four lists inside dict_list as separate arguments to zip.

zip(dict_list['First Name'], dict_list['Last Name'], dict_list['Age'], dict_list['Occupation'])

Both of them end up passing the exact same thing to zip(). Naturally, the result is the same.


If you want to compare it to a version without the *, try:

zip(dict_list.values())

Now there's a difference:

>>> zip(*dict_list.values())
[('Haverford', 'Tom', 33, 'Administrator'), ('Perkins', 'Ann', 42, 'Nurse'), ('Wyatt', 'Ben', 44, 'Auditor')]
>>> zip(dict_list.values())
[(['Haverford', 'Perkins', 'Wyatt'],), (['Tom', 'Ann', 'Ben'],), ([33, 42, 44],), (['Administrator', 'Nurse', 'Auditor'],)]
John Kugelman
  • 349,597
  • 67
  • 533
  • 578