13

I've a zip object and I want to sort it(based on a specific key).

I've already seen How do I sort a zipped list in Python? but the accepted answer does not work in python 3.6 anymore.

For example

In [6]: a = [3,9,2,24,1,6]

In [7]: b = ['a','b','c','d','e']

In [8]: c = zip(a,b)

In [9]: c
Out[9]: <zip at 0x108f59ac8>

In [11]: type(c)
Out[11]: zip

In [12]: c.sort()
---------------------------------------------------------------------------
AttributeError                            Traceback (most recent call last)
<ipython-input-12-a21727fa8976> in <module>()
----> 1 c.sort()

AttributeError: 'zip' object has no attribute 'sort'

# Wanted this to be sorted by the first element
In [13]: for l,r in c: print(l,r)
3 a
9 b
2 c
24 d
1 e

In other words how do I make the zip iteration order conform to the sorting order. I'm aware that converting a zip to a list of tuples will allow me to fix this, but I want to retain the zipped object (as it used to be in the good old days of python2.7)

Community
  • 1
  • 1
Anoop
  • 5,540
  • 7
  • 35
  • 52
  • Well, the second answer to the linked question works in python3. – MSeifert Apr 29 '17 at 17:32
  • 1
    2.7 didn't have a "zip object": `zip()` returned a list in Python 2. So if you changed your code to `c = list(zip(a,b))` in Python 3, it would behave exactly as it did in Python 2. – Tim Peters Apr 29 '17 at 17:33
  • 1
    @anoop There are other answers besides the accepted one that should solve your problem, so I'm closing this as a duplicate. – zondo Apr 29 '17 at 17:44

2 Answers2

22

zip() in Python 3 returns an iterator; the inputs are zipped as you request elements from it. Iterators are not sortable, no.

You can use the sorted() function to 'draw out' the elements and return a sorted list from them:

sorted(zip(a, b))

You could also convert the zip() object to a list by calling list() on it, then sort that result in-place with the list.sort() method, but that's then more work than just using the sorted() function.

sorted() takes the same keyword arguments as list.sort() does, so you can still use the same key function:

Demo:

>>> a = [3, 9, 2, 24, 1, 6]
>>> b = ['a', 'b', 'c', 'd', 'e']
>>> sorted(zip(a, b))
[(1, 'e'), (2, 'c'), (3, 'a'), (9, 'b'), (24, 'd')]
>>> sorted(zip(a, b), key=lambda x: x[1])
[(3, 'a'), (9, 'b'), (2, 'c'), (24, 'd'), (1, 'e')]

Also see What is the difference between `sorted(list)` vs `list.sort()` ? python

Martijn Pieters
  • 1,048,767
  • 296
  • 4,058
  • 3,343
5

You can't use sort on zip object, zip object doesn't have such attribute. But, you can convert the zip object to a list with list(zipped_object) and then apply sort on it, to do an in-place sort.

But, as zipped object is also an iterable, my recommendation is to use sorted(). It will let you write a sort function also, based on which the collection will be sorted.

Here, I am sorting it based on the values of y in each (x,y) pair. .

>>> a = [3,9,2,24,1,6]
>>> b = ['a','b','c','d','e']
>>> c = zip(a,b)
>>> 
>>> sorted(c, key = lambda x:x[1])
[(3, 'a'), (9, 'b'), (2, 'c'), (24, 'd'), (1, 'e')]

Note that, sorted will return a new sorted list, whereas sort will sort the collection in place.

Ahsanul Haque
  • 10,676
  • 4
  • 41
  • 57