sorting list of complex numbers

Diez B. Roggisch deets at nospam.web.de
Sun Nov 9 16:19:50 CET 2008

```skip at pobox.com schrieb:
> The thread on sorting in Python 3 got me to thinking.  How could I sort a
> list of complex numbers using key?
>
>     >>> lst = [random.random()+random.random()*1j for i in range(10)]
>     >>> lst
>     [(0.32672251849959244+0.41428983433288791j), (0.35238056484609881+0.92758203977208264j), (0.19337824038125528+0.16527285180541951j), (0.47569307114525849+0.72381960418815128j), (0.21498813135082351+0.2046308266222292j), (0.30142745756937939+0.35216751451102601j), (0.77355676386939132+0.0023447924287695043j), (0.2547736124606309+0.52234837788936905j), (0.38349189081350132+0.62017617694427096j), (0.58362096773561245+0.87702443273108477j)]
>
> As expected:
>
>     >>> sorted(lst)
>     Traceback (most recent call last):
>       File "<stdin>", line 1, in <module>
>     TypeError: no ordering relation is defined for complex numbers
>
> This works:
>
>     >>> sorted(lst, key=lambda x: x.real)
>     [(0.19337824038125528+0.16527285180541951j), (0.21498813135082351+0.2046308266222292j), (0.2547736124606309+0.52234837788936905j), (0.30142745756937939+0.35216751451102601j), (0.32672251849959244+0.41428983433288791j), (0.35238056484609881+0.92758203977208264j), (0.38349189081350132+0.62017617694427096j), (0.47569307114525849+0.72381960418815128j), (0.58362096773561245+0.87702443273108477j), (0.77355676386939132+0.0023447924287695043j)]
>
> but what if I want to sort by real, then imaginary parts?  Here's a longer
> list with 20 elements where there are only 10 distinct reals but 20 distinct
> imaginaries:
>
>     >>> pprint.pprint(lst)
>     [(1+2.73j),
>      (9+3.77j),
>      (7+27j),
>      (8+28j),
>      (2+2.8600000000000003j),
>      (4+3.1200000000000001j),
>      (2+22j),
>      (9+29j),
>      (3+2.9900000000000002j),
>      (6+26j),
>      2.6000000000000001j,
>      (8+3.6400000000000001j),
>      (3+23j),
>      (5+3.25j),
>      (1+21j),
>      (5+25j),
>      20j,
>      (6+3.3799999999999999j),
>      (7+3.5100000000000002j),
>      (4+24j)]
>
> I can sort by the real parts just fine:
>
>     >>> lst.sort(key=lambda x: x.real)
>     >>> pprint.pprint(lst)
>     [2.6000000000000001j,
>      20j,
>      (1+2.73j),
>      (1+21j),
>      (2+2.8600000000000003j),
>      (2+22j),
>      (3+2.9900000000000002j),
>      (3+23j),
>      (4+3.1200000000000001j),
>      (4+24j),
>      (5+3.25j),
>      (5+25j),
>      (6+26j),
>      (6+3.3799999999999999j),
>      (7+27j),
>      (7+3.5100000000000002j),
>      (8+28j),
>      (8+3.6400000000000001j),
>      (9+3.77j),
>      (9+29j)]
>
> but how do I then do a secondary sort by the imaginary part, preserving the
> existing ordering on the real parts?  Seems like I have to resort to a
> Schwartzian transform and map the complex numbers to tuples, sort that, then
> map them back.  With the cmp key it would have been a fairly trivial task to
> define the desired compare-real-then-imag function.
>
> Is there a way to do this using just the key arg, no extra data structures?

Doesn't (untested)

key=lambda x: (x.real, x.imag)

work?

Diez

```