Sorting Multidimesional array(newbie)

T

Tartifola

Hi,
how can I sort an array like

array([[5, 2],
[1, 3]])

along the first column to obtain

array([[1, 3],
[5, 2]])
i.e. keeping track of the ordered couples?

Thanks,
A
 
P

Peter Otten

Matimus said:
Tartifola said:
Hi,
how can I sort an array like

array([[5, 2],
[1, 3]])

along the first column to obtain

array([[1, 3],
[5, 2]])
i.e. keeping track of the ordered couples?

Thanks,
A

use a sort key:
from operators import getitem
a = [[5,2],[1,3]]
a [[5, 2], [1, 3]]
a.sort(key=lambda x:getitem(x,0))
a
[[1, 3], [5, 2]]

Is that a faked session?
Traceback (most recent call last):
from operator import itemgetter
a = [[5, 2], [1, 3]]
a.sort(key=itemgetter(0))
a
[[1, 3], [5, 2]]

Peter
 
B

Brian Mills

There's another (IMHO more readable) way to do it if you can afford
.... if lst1[0] < lst2[0]: return -1
.... if lst2[0] > lst2[0]: return 1
.... return 0
....
a = [[5, 2], [1, 3]]
a [[5, 2], [1, 3]]
a.sort(cmp=myListCmp)
a [[1, 3], [5, 2]]

Matimus said:
Tartifola said:
Hi,
how can I sort an array like
array([[5, 2],
[1, 3]])
along the first column to obtain
array([[1, 3],
[5, 2]])
i.e. keeping track of the ordered couples?
Thanks,
A
use a sort key:
from operators import getitem
a = [[5,2],[1,3]]
a [[5, 2], [1, 3]]
a.sort(key=lambda x:getitem(x,0))
a
[[1, 3], [5, 2]]Is that a faked session?
from operators import getitemTraceback (most recent call last):
from operator import itemgetter
a = [[5, 2], [1, 3]]
a.sort(key=itemgetter(0))
a[[1, 3], [5, 2]]

Peter
 
F

Fredrik Lundh

Brian said:
There's another (IMHO more readable) way to do it if you can afford
... if lst1[0] < lst2[0]: return -1
... if lst2[0] > lst2[0]: return 1
... return 0

shorter:

def myListCmp(a, b):
return cmp(a[0], b[0])

but using a compare function instead of a key mapper is not good advice,
in general. brief discussion here:

http://effbot.org/pyfaq/i-want-to-do-a-complicated-sort-can-you-do-a-schwartzian-transform-in-python

also note the OP didn't specify what to do for records where the first
column was identical, so I guess a plain sort() call, without any custom
compares or mappings, would work as well as the fancier alternatives...

</F>
 
R

Robert Kern

Fredrik said:
also note the OP didn't specify what to do for records where the first
column was identical, so I guess a plain sort() call, without any custom
compares or mappings, would work as well as the fancier alternatives...

If the OP had lists of lists, yes. However, he seems to be using one of (numpy,
numarray, Numeric). Because of rich comparisons, just using sorted() won't work.
The cheap and cheerful approach would be to convert to lists of lists using
..tolist(), .sort() the list, and then reconstruct the array object. Depending on
the size of the array, that may be just fine.

numpy (and maybe numarray, I'd have to check) has a function lexsort(), which
unfortunately has a confusing interface.


In [2]: lexsort?
Type: builtin_function_or_method
Base Class: <type 'builtin_function_or_method'>
Namespace: Interactive
Docstring:
lexsort(keys=, axis=-1) -> array of indices. argsort with list of keys.

Return an array of indices similar to argsort, except the sorting is
done using the provided sorting keys. First the sort is done using
key[0], then the resulting list of indices is further manipulated by
sorting on key[1], and so forth. The result is a sort on multiple
keys. If the keys represented columns of a spreadsheet, for example,
this would sort using multiple columns (the last key being used for the
primary sort order, the second-to-last key for the secondary sort order,
and so on). The keys argument must be a sequence of things that can be
converted to arrays of the same shape.


This is the idiomatic way to lexicographically sort an array by columns
equivalent to the .tolist() approach I give above. I usually wrap lexsort() with
these operations so my brain doesn't explode.


In [15]: from numpy import *

In [16]: a = array([[5, 2], [1, 3], [1, 2]])

In [17]: a[lexsort(keys=a.transpose()[::-1])]
Out[17]:
array([[1, 2],
[1, 3],
[5, 2]])

--
Robert Kern

"I have come to believe that the whole world is an enigma, a harmless enigma
that is made terrible by our own mad attempt to interpret it as though it had
an underlying truth."
-- Umberto Eco
 
T

Travis E. Oliphant

Tartifola said:
Hi,
how can I sort an array like

array([[5, 2],
[1, 3]])

along the first column to obtain

array([[1, 3],
[5, 2]])
i.e. keeping track of the ordered couples?

Thanks,
A

Just to add one more solution to this question that works with numpy.

You can also view the array using fields and then sort (which will do
lexicographic ordering) and convert the result back to the original view.

Something like this:

a = array([[5,2],[1,3]])
dt = a.dtype
g = a.view([('',dt),('',dt)])
g.sort(0)
a = g.view(dt)


-Travis
 
B

Brian Mills

Fredrik said:
Brian said:
There's another (IMHO more readable) way to do it if you can afford
def myListCmp(lst1, lst2):
... if lst1[0] < lst2[0]: return -1
... if lst2[0] > lst2[0]: return 1
... return 0

shorter:

def myListCmp(a, b):
return cmp(a[0], b[0])

Good point.
but using a compare function instead of a key mapper is not good advice,
in general. brief discussion here:
http://effbot.org/pyfaq/i-want-to-do-a-complicated-sort-can-you-do-a-schwartzian-transform-in-python

Is this mostly because of the stability problem described here:
http://aspn.activestate.com/ASPN/Cookbook/Python/Recipe/52234 ? Or is
it more a performance issue due having to make so many function calls?
also note the OP didn't specify what to do for records where the first
column was identical, so I guess a plain sort() call, without any custom
compares or mappings, would work as well as the fancier alternatives...

I can't believe I didn't try this, but for the given example it works
perfectly. It even acts gracefully when you give it such sociopathic
lists as
c = [[3, 1], [8, 2], [6, 3], [12, 4], [1, 5], ["oh noes!", 6], [24, 7], [ope n("file.txt", 'r'), 8], [[1, 2, 3], 9]]
c.sort()
c
[[1, 5], [3, 1], [6, 3], [8, 2], [12, 4], [24, 7], [<open file
'file.txt', mode
'r' at 0x00A65608>, 8], [[1, 2, 3], 9], ['oh noes!', 6]]

Though changing the ordering system it decides to use may take some
more research.
 
P

Peter Otten

Brian said:
http://effbot.org/pyfaq/i-want-to-do-a-complicated-sort-can-you-do-a-schwartzian-transform-in-python

Is this mostly because of the stability problem described here:
http://aspn.activestate.com/ASPN/Cookbook/Python/Recipe/52234 ? Or is
it more a performance issue due having to make so many function calls?

http://docs.python.org/lib/typesseq-mutable.html

"""Starting with Python 2.3, the sort() method is guaranteed to be
stable."""

So performance it is. It is also often simpler once you get used to it and
start seeing the pattern

def mycmp(a, b):
return cmp(mykey(a), mykey(b))

in many of your custom comparison functions.

Peter
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,756
Messages
2,569,535
Members
45,008
Latest member
obedient dusk

Latest Threads

Top