Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

Pythonic list reordering

0 views
Skip to first unread message

Ben Racine

unread,
Apr 8, 2010, 6:52:08 PM4/8/10
to pytho...@python.org
I have a list...

['dir_0_error.dat', 'dir_120_error.dat', 'dir_30_error.dat', 'dir_330_error.dat']

I want to sort it based upon the numerical value only.

Does someone have an elegant solution to this?

Thanks,
Ben R.

Chris Rebert

unread,
Apr 8, 2010, 6:54:59 PM4/8/10
to Ben Racine, pytho...@python.org
On Thu, Apr 8, 2010 at 3:52 PM, Ben Racine <i3en...@gmail.com> wrote:
> I have a list...
>
> ['dir_0_error.dat', 'dir_120_error.dat', 'dir_30_error.dat', 'dir_330_error.dat']
>
> I want to sort it based upon the numerical value only.

a = ['dir_0_error.dat', 'dir_120_error.dat', 'dir_30_error.dat',
'dir_330_error.dat']
def key(item):
return int(item.split('_')[1])
a.sort(key=key)

Cheers,
Chris
--
http://blog.rebertia.com

Gary Herron

unread,
Apr 8, 2010, 6:59:34 PM4/8/10
to Ben Racine, pytho...@python.org
Ben Racine wrote:
> I have a list...
>
> ['dir_0_error.dat', 'dir_120_error.dat', 'dir_30_error.dat', 'dir_330_error.dat']
>
> I want to sort it based upon the numerical value only.
>
> Does someone have an elegant solution to this?
>
> Thanks,
> Ben R.
>

How about a one liner?

L.sort(key=lambda s: int(s.split('_')[1]))


(Which is not necessarily elegant, but it is short.)

Gary Herron

Joaquin Abian

unread,
Apr 8, 2010, 7:01:08 PM4/8/10
to

not sure about elegance, but my two cents:

>> mylist = ['dir_0_error.dat', 'dir_120_error.dat', 'dir_30_error.dat', 'dir_330_error.dat']
>> mylist = [(int(item.split('_')[1]), item) for item in mylist]
>> mylist.sort()
>> mylist = [item for idx, item in mylist]
>> mylist

['dir_0_error.dat', 'dir_30_error.dat', 'dir_120_error.dat',
'dir_330_error.dat']

joaquin

Lie Ryan

unread,
Apr 8, 2010, 8:43:16 PM4/8/10
to

list.sort() and sorted() accept `key` argument, which receives a
callable that transform the item to be sorted into sorting key. So if
you have:

l = ['dir_30_error.dat', 'dir_120_error.dat',
'dir_330_error.dat', 'dir_0_error.dat']

# 'dir_0_error.dat' -> 0
# 'dir_30_error.dat' -> 30
def getnum(s):
return int(''.join(x for x in s if x.isdigit()))

# sort based on getnum()'s return value
l.sort(key=getnum)

Chris Rebert

unread,
Apr 8, 2010, 7:58:39 PM4/8/10
to Joaquin Abian, pytho...@python.org
On Thu, Apr 8, 2010 at 4:01 PM, Joaquin Abian <gatoy...@gmail.com> wrote:
> On Apr 9, 12:52 am, Ben Racine <i3enha...@gmail.com> wrote:
>> I have a list...
>>
>> ['dir_0_error.dat', 'dir_120_error.dat', 'dir_30_error.dat', 'dir_330_error.dat']
>>
>> I want to sort it based upon the numerical value only.
>>
>> Does someone have an elegant solution to this?
>
> not sure about elegance, but my two cents:
>
>>> mylist = ['dir_0_error.dat', 'dir_120_error.dat', 'dir_30_error.dat', 'dir_330_error.dat']
>>> mylist = [(int(item.split('_')[1]), item) for item in mylist]
>>> mylist.sort()
>>> mylist = [item for idx, item in mylist]
>>> mylist
>
> ['dir_0_error.dat', 'dir_30_error.dat', 'dir_120_error.dat',
> 'dir_330_error.dat']

At least conceptually, that's how list.sort() with a key= argument
works internally (i.e. via Schwartzian transform).

Joaquin Abian

unread,
Apr 9, 2010, 9:21:26 AM4/9/10
to
On Apr 9, 1:58 am, Chris Rebert <c...@rebertia.com> wrote:

Chris, thanks for the comment. I did not know that name (Schwartzian
transform)
I knew it as the decorate-sort-undecorate strategy.
Now after learning that it was a Perl idiom I feel somewhat
embarrassed ;-)

BTW, I actually prefer the l.sort(key=f) method.
Just my lazy neurons were back to Python 2.3 when I wrote the
response.

Joaquin

Tobiah

unread,
Apr 9, 2010, 12:19:58 PM4/9/10
to

> How about a one liner?
>
> L.sort(key=lambda s: int(s.split('_')[1]))
>
> (Which is not necessarily elegant, but it is short.)

I grant it a measure of elegance as well.

Kent Engström

unread,
Apr 10, 2010, 7:31:35 AM4/10/10
to pytho...@python.org
Ben Racine <i3en...@gmail.com> writes:
> I have a list...
>
> ['dir_0_error.dat', 'dir_120_error.dat', 'dir_30_error.dat', 'dir_330_error.dat']
>
> I want to sort it based upon the numerical value only.
>
> Does someone have an elegant solution to this?

I use code like the hack below to sort miscellaneous strings that
consist of mixed numerical and non-numerical parts.

import re

nsk_re = re.compile("([0-9]+)|([^0-9]+)")
def numeric_sort_key(x):
return [handle_int_nonint(i_ni) for i_ni in nsk_re.findall(x)]

def handle_int_nonint(int_nonint_tuple):
if int_nonint_tuple[0]:
return int(int_nonint_tuple[0])
else:
return int_nonint_tuple[1]

def numerically_sorted(l):
return sorted(l, key=numeric_sort_key)

alex23

unread,
Apr 10, 2010, 10:51:30 AM4/10/10
to

This approach doesn't rely on knowing the format of the string:

>>> from string import maketrans, letters, punctuation
>>> a = ['dir_0_error.dat', 'dir_120_error.dat', 'dir_30_error.dat', 'dir_330_error.dat']
>>> def only_numbers(s):
... nums = s.translate(None, letters+punctuation)
... return int(nums)
...
>>> a.sort(key=only_numbers)
>>> a


['dir_0_error.dat', 'dir_30_error.dat', 'dir_120_error.dat',
'dir_330_error.dat']

If you're using Python 3.x, the string module has been removed, so you
can find the maketrans function on str there.

MRAB

unread,
Apr 10, 2010, 11:04:26 AM4/10/10
to pytho...@python.org

The string module still exists in Python 3.x, but the string functions
which have been superseded by string methods have been removed.

alex23

unread,
Apr 10, 2010, 11:20:33 AM4/10/10
to
MRAB <pyt...@mrabarnett.plus.com> wrote:
> The string module still exists in Python 3.x, but the string functions
> which have been superseded by string methods have been removed.

Awesome, thanks for the heads up.

0 new messages