<?xml version="1.0" encoding="UTF-8"?><!-- generator="wordpress/2.2" -->
<rss version="2.0" 
	xmlns:content="http://purl.org/rss/1.0/modules/content/">
<channel>
	<title>Comments on: Reverse sorting on arbitrary key segments</title>
	<link>http://ramblings.timgolden.me.uk/2009/10/15/reverse-sorting-on-arbitrary-key-segments/</link>
	<description>The ramblings of Tim Golden</description>
	<pubDate>Thu, 09 Sep 2010 04:50:13 +0000</pubDate>
	<generator>http://wordpress.org/?v=2.2</generator>

	<item>
		<title>By: tim</title>
		<link>http://ramblings.timgolden.me.uk/2009/10/15/reverse-sorting-on-arbitrary-key-segments/#comment-1022</link>
		<author>tim</author>
		<pubDate>Fri, 16 Oct 2009 08:05:16 +0000</pubDate>
		<guid>http://ramblings.timgolden.me.uk/2009/10/15/reverse-sorting-on-arbitrary-key-segments/#comment-1022</guid>
		<description>@manuelmoeg: Thanks for the bouquets. I believe that the particular reason to avoid the cmp function approach (apart from the fact that it no longer exists in Python 3.x) is that it is called for *every* comparison while the key function is called only for every item in the iterable. If I'd had to decorate each item with an auxiliary class in a cmp function I think performance would have suffered unduly. (Altho' I haven't run any timings).</description>
		<content:encoded><![CDATA[<p>@manuelmoeg: Thanks for the bouquets. I believe that the particular reason to avoid the cmp function approach (apart from the fact that it no longer exists in Python 3.x) is that it is called for *every* comparison while the key function is called only for every item in the iterable. If I&#8217;d had to decorate each item with an auxiliary class in a cmp function I think performance would have suffered unduly. (Altho&#8217; I haven&#8217;t run any timings).</p>
]]></content:encoded>
	</item>
	<item>
		<title>By: tim</title>
		<link>http://ramblings.timgolden.me.uk/2009/10/15/reverse-sorting-on-arbitrary-key-segments/#comment-1021</link>
		<author>tim</author>
		<pubDate>Fri, 16 Oct 2009 07:59:16 +0000</pubDate>
		<guid>http://ramblings.timgolden.me.uk/2009/10/15/reverse-sorting-on-arbitrary-key-segments/#comment-1021</guid>
		<description>Thanks to those who pointed out my misunderstanding of the wiki page. I knew that the Python sort was stable (altho' I could never remember whether that's guaranteed in all version / implementations or merely an artefact of the current CPython code). But I hadn't appreciated the sort-backwards trick.

@pruebauno: As I mentioned, specific optimisations for known datatypes won't help me for the general case I'm trying to achieve.

@Travis: I'll have a look at that page but since I don't have numpy or its relatives installed on any of the machines I use it would be quite an overhead to achieve one sort -- no matter how efficiently :)</description>
		<content:encoded><![CDATA[<p>Thanks to those who pointed out my misunderstanding of the wiki page. I knew that the Python sort was stable (altho&#8217; I could never remember whether that&#8217;s guaranteed in all version / implementations or merely an artefact of the current CPython code). But I hadn&#8217;t appreciated the sort-backwards trick.</p>
<p>@pruebauno: As I mentioned, specific optimisations for known datatypes won&#8217;t help me for the general case I&#8217;m trying to achieve.</p>
<p>@Travis: I&#8217;ll have a look at that page but since I don&#8217;t have numpy or its relatives installed on any of the machines I use it would be quite an overhead to achieve one sort &#8212; no matter how efficiently :)</p>
]]></content:encoded>
	</item>
	<item>
		<title>By: Travis Vaught</title>
		<link>http://ramblings.timgolden.me.uk/2009/10/15/reverse-sorting-on-arbitrary-key-segments/#comment-1020</link>
		<author>Travis Vaught</author>
		<pubDate>Thu, 15 Oct 2009 20:04:38 +0000</pubDate>
		<guid>http://ramblings.timgolden.me.uk/2009/10/15/reverse-sorting-on-arbitrary-key-segments/#comment-1020</guid>
		<description>Have you tried a numpy structured array, rather than a list of dicts?  The final example on this page seems to do what you want:

http://docs.scipy.org/doc/numpy/reference/generated/numpy.sort.html</description>
		<content:encoded><![CDATA[<p>Have you tried a numpy structured array, rather than a list of dicts?  The final example on this page seems to do what you want:</p>
<p><a href="http://docs.scipy.org/doc/numpy/reference/generated/numpy.sort.html" rel="nofollow">http://docs.scipy.org/doc/numpy/reference/generated/numpy.sort.html</a></p>
]]></content:encoded>
	</item>
	<item>
		<title>By: pruebauno@latinmail.com</title>
		<link>http://ramblings.timgolden.me.uk/2009/10/15/reverse-sorting-on-arbitrary-key-segments/#comment-1019</link>
		<author>pruebauno@latinmail.com</author>
		<pubDate>Thu, 15 Oct 2009 18:20:03 +0000</pubDate>
		<guid>http://ramblings.timgolden.me.uk/2009/10/15/reverse-sorting-on-arbitrary-key-segments/#comment-1019</guid>
		<description>In your particular case something like this (untested) could have worked too:

sorted(rows,key=lambda x:(x['names'],-x['age']))</description>
		<content:encoded><![CDATA[<p>In your particular case something like this (untested) could have worked too:</p>
<p>sorted(rows,key=lambda x:(x[&#8217;names&#8217;],-x[&#8217;age&#8217;]))</p>
]]></content:encoded>
	</item>
	<item>
		<title>By: Ian Collins</title>
		<link>http://ramblings.timgolden.me.uk/2009/10/15/reverse-sorting-on-arbitrary-key-segments/#comment-1018</link>
		<author>Ian Collins</author>
		<pubDate>Thu, 15 Oct 2009 17:00:27 +0000</pubDate>
		<guid>http://ramblings.timgolden.me.uk/2009/10/15/reverse-sorting-on-arbitrary-key-segments/#comment-1018</guid>
		<description>Sorting by each key in turn does work if you take the keys in reverse order i.e. in your example, by age (descending) and then by name (ascending). It works because Python's sort algorithm is "stable", meaning that if item A starts off above item B and for the purposes of the sort A and B evaluate equal, A will still be above B after the sort. I think I read somewhere that the sort algorithm is guaranteed to remain stable in future Python releases.</description>
		<content:encoded><![CDATA[<p>Sorting by each key in turn does work if you take the keys in reverse order i.e. in your example, by age (descending) and then by name (ascending). It works because Python&#8217;s sort algorithm is &#8220;stable&#8221;, meaning that if item A starts off above item B and for the purposes of the sort A and B evaluate equal, A will still be above B after the sort. I think I read somewhere that the sort algorithm is guaranteed to remain stable in future Python releases.</p>
]]></content:encoded>
	</item>
	<item>
		<title>By: http://manuelmoeg.blogspot.com/</title>
		<link>http://ramblings.timgolden.me.uk/2009/10/15/reverse-sorting-on-arbitrary-key-segments/#comment-1017</link>
		<author>http://manuelmoeg.blogspot.com/</author>
		<pubDate>Thu, 15 Oct 2009 16:38:56 +0000</pubDate>
		<guid>http://ramblings.timgolden.me.uk/2009/10/15/reverse-sorting-on-arbitrary-key-segments/#comment-1017</guid>
		<description>TL;DR Great!  If Raymond Hettinger comes up with another way, use that, but yours is great!

What I like about your approach:

1) trivial to see that the sort is correct

With Python's stable sort, there is always a combination of mixing these three [(A) ascending sorts on a key, (B) reversed sorts on a key, (C) reversing the list] that will do the job, but it can be confusing to work out the pattern, and I don't know the logic to compute the patter given any list of keys and asc/desc.

The !!!testing!!! on any approach is the killer.  If you are not obligated to be correct on the corner cases, it is easy to implement.

Your technique, it is either 100% correct, or it will fail plainly.

2) faster than "cmp"

usually, implementing a combination of ascending and descending sorts is done with the "cmp" option of providing "sort" a "cmp" function.  If the first column is an ascending sort, your approach will blow away any "cmp" function, and I believe your technique will be faster in all cases, than using "cmp"

3) less code than an implementation that mixes sorts with reverses

If somebody codes up a correct implementation that mixes [(A) ascending sorts on a key, (B) reversed sorts on a key, (C) reversing the list] to do the work, it will be faster and use less resources than your technique.  But it will take more code.</description>
		<content:encoded><![CDATA[<p>TL;DR Great!  If Raymond Hettinger comes up with another way, use that, but yours is great!</p>
<p>What I like about your approach:</p>
<p>1) trivial to see that the sort is correct</p>
<p>With Python&#8217;s stable sort, there is always a combination of mixing these three [(A) ascending sorts on a key, (B) reversed sorts on a key, (C) reversing the list] that will do the job, but it can be confusing to work out the pattern, and I don&#8217;t know the logic to compute the patter given any list of keys and asc/desc.</p>
<p>The !!!testing!!! on any approach is the killer.  If you are not obligated to be correct on the corner cases, it is easy to implement.</p>
<p>Your technique, it is either 100% correct, or it will fail plainly.</p>
<p>2) faster than &#8220;cmp&#8221;</p>
<p>usually, implementing a combination of ascending and descending sorts is done with the &#8220;cmp&#8221; option of providing &#8220;sort&#8221; a &#8220;cmp&#8221; function.  If the first column is an ascending sort, your approach will blow away any &#8220;cmp&#8221; function, and I believe your technique will be faster in all cases, than using &#8220;cmp&#8221;</p>
<p>3) less code than an implementation that mixes sorts with reverses</p>
<p>If somebody codes up a correct implementation that mixes [(A) ascending sorts on a key, (B) reversed sorts on a key, (C) reversing the list] to do the work, it will be faster and use less resources than your technique.  But it will take more code.</p>
]]></content:encoded>
	</item>
	<item>
		<title>By: Kent Johnson</title>
		<link>http://ramblings.timgolden.me.uk/2009/10/15/reverse-sorting-on-arbitrary-key-segments/#comment-1016</link>
		<author>Kent Johnson</author>
		<pubDate>Thu, 15 Oct 2009 16:11:01 +0000</pubDate>
		<guid>http://ramblings.timgolden.me.uk/2009/10/15/reverse-sorting-on-arbitrary-key-segments/#comment-1016</guid>
		<description>You have mis-read the sorting page on the wiki. It is confusing because the primary sort in the example is the second element, the secondary sort is the first element. What it is saying is sort in reverse order of significance of the keys. Because Python sort is guaranteed to preserve order of equal items, this will give the result you want.

In [1]: from operator import itemgetter

In [2]: rows = [
   ...:   dict (name="John", age=30, id=123),
   ...:   dict (name="John", age=40, id=456),
   ...:   dict (name="Fred", age=20, id=567),
   ...: ]

In [3]: rows.sort(key=itemgetter('age'), reverse=True)

In [4]: rows
Out[4]:
[{'age': 40, 'id': 456, 'name': 'John'},
 {'age': 30, 'id': 123, 'name': 'John'},
 {'age': 20, 'id': 567, 'name': 'Fred'}]

In [5]: rows.sort(key=itemgetter('name'))

In [6]: rows
Out[6]:
[{'age': 20, 'id': 567, 'name': 'Fred'},
 {'age': 40, 'id': 456, 'name': 'John'},
 {'age': 30, 'id': 123, 'name': 'John'}]</description>
		<content:encoded><![CDATA[<p>You have mis-read the sorting page on the wiki. It is confusing because the primary sort in the example is the second element, the secondary sort is the first element. What it is saying is sort in reverse order of significance of the keys. Because Python sort is guaranteed to preserve order of equal items, this will give the result you want.</p>
<p>In [1]: from operator import itemgetter</p>
<p>In [2]: rows = [<br />
   &#8230;:   dict (name=&#8221;John&#8221;, age=30, id=123),<br />
   &#8230;:   dict (name=&#8221;John&#8221;, age=40, id=456),<br />
   &#8230;:   dict (name=&#8221;Fred&#8221;, age=20, id=567),<br />
   &#8230;: ]</p>
<p>In [3]: rows.sort(key=itemgetter(&#8217;age&#8217;), reverse=True)</p>
<p>In [4]: rows<br />
Out[4]:<br />
[{&#8217;age&#8217;: 40, &#8216;id&#8217;: 456, &#8216;name&#8217;: &#8216;John&#8217;},<br />
 {&#8217;age&#8217;: 30, &#8216;id&#8217;: 123, &#8216;name&#8217;: &#8216;John&#8217;},<br />
 {&#8217;age&#8217;: 20, &#8216;id&#8217;: 567, &#8216;name&#8217;: &#8216;Fred&#8217;}]</p>
<p>In [5]: rows.sort(key=itemgetter(&#8217;name&#8217;))</p>
<p>In [6]: rows<br />
Out[6]:<br />
[{&#8217;age&#8217;: 20, &#8216;id&#8217;: 567, &#8216;name&#8217;: &#8216;Fred&#8217;},<br />
 {&#8217;age&#8217;: 40, &#8216;id&#8217;: 456, &#8216;name&#8217;: &#8216;John&#8217;},<br />
 {&#8217;age&#8217;: 30, &#8216;id&#8217;: 123, &#8216;name&#8217;: &#8216;John&#8217;}]</p>
]]></content:encoded>
	</item>
</channel>
</rss>
