<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>scienceoss.com &#187; key</title>
	<atom:link href="http://scienceoss.com/tags/key/feed/" rel="self" type="application/rss+xml" />
	<link>http://scienceoss.com</link>
	<description>useful tidbits for using open source software in science</description>
	<lastBuildDate>Wed, 26 May 2010 03:34:19 +0000</lastBuildDate>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.org/?v=3.3.2</generator>
		<item>
		<title>Advanced sorting: sorting by key</title>
		<link>http://scienceoss.com/advanced-sorting-sorting-by-key/</link>
		<comments>http://scienceoss.com/advanced-sorting-sorting-by-key/#comments</comments>
		<pubDate>Mon, 14 Apr 2008 18:30:29 +0000</pubDate>
		<dc:creator>ryan</dc:creator>
				<category><![CDATA[Python]]></category>
		<category><![CDATA[key]]></category>
		<category><![CDATA[sort]]></category>

		<guid isPermaLink="false">http://scienceoss.com/advanced-sorting-sorting-by-key/</guid>
		<description><![CDATA[The sort() method of list objects in Python is quite flexible. By default, it sorts on the first thing in each item of the list, which is exactly what you would expect. For example, a list of strings is sorted by the first letter of each string. What if you wanted to sort by the [...]]]></description>
			<content:encoded><![CDATA[<p>The <span class="c">sort()</span> method of list objects in Python is quite flexible.  By default, it sorts on the first thing in each item of the list, which is exactly what you would expect.  For example, a list of strings is sorted by the first letter of each string.    What if you wanted to sort by the second letter of each string?  Or sort a list of people&#8217;s names by last name?<span id="more-110"></span></p>
<p>By default, the <span class="c">key</span> to sort by is the first letter of each string.  Or the first item in a sequence if it&#8217;s list of sequences.  But Python allows you to specify any key that you want, using the <span class="c">key</span> parameter for the <span class="c">sort()</span> function.  The <span class="c">key</span> is the name of a function.  </p>
<p>The way it works is this:  <span class="c">sort</span> runs every item in the list through the function.  Whatever the function returns is used to sort, overriding the default of using the first thing.  </p>
<h3>Example 1</h3>
<p>So to sort a list of strings by the second letter instead of the first letter then we simply need a function that returns the second letter of a string.  Here&#8217;s such a function, and how to use it as a key to <span class="c">sort</span>.  Note that <span class="c">key=secondletter</span>, NOT <span class="c">key=secondletter()</span>.  We&#8217;re specifying the reference to <span class="c">secondletter</span>, not trying to call it.</p>
<pre class="brush: python; title: ; notranslate">
def secondletter(x):
    return x[1]

mylist = ['orange', 'banana', 'apple']

mylist.sort(key=secondletter)

# ['banana', 'apple', 'orange']
</pre>
<p>By the way, for simple one-liner functions like this, we could have used the <a href="http://docs.python.org/tut/node6.html#SECTION006750000000000000000">lambda syntax</a> instead of defining the <span class="c">secondletter</span> function:</p>
<pre class="brush: python; title: ; notranslate">
mylist = ['orange', 'banana', 'apple']
mylist.sort(key=lambda x: x[1])
</pre>
<h3>Example 2</h3>
<p>OK, while it&#8217;s a good first example, sorting on the second letter isn&#8217;t terribly useful.  How about sorting a list of people&#8217;s names by their last name?  We simply need a function to return the last name, and use the name of that function as the sort key.</p>
<pre class="brush: python; title: ; notranslate">def lastname(x):
    firstname, lastname = x.split()
    return lastname

presidents = ['Abraham Lincoln', 'George Washington',
              'Benjamin Harrison', 'Millard Fillmore']

presidents.sort(key=lastname)

#['Millard Fillmore',
# 'Benjamin Harrison',
# 'Abraham Lincoln',
# 'George Washington']
</pre>
<p>Of course, in practice you would have to be careful with this . . . if there&#8217;s a middle name in there, then it would break the <span class="c">lastname</span> function.  This one works better:</p>
<pre class="brush: python; title: ; notranslate">
def lastname2(x):
        return x.split()[-1]

not_all_presidents = ['Abraham Lincoln', 'George Washington', 'Benjamin Harrison',
                     'Millard Fillmore', 'Prince', 'Madonna', 'Arthur C. Clarke']

not_all_presidents.sort(key=lastname2)

#['Arthur C. Clarke',
# 'Millard Fillmore',
# 'Benjamin Harrison',
# 'Abraham Lincoln',
# 'Madonna',
# 'Prince',
# 'George Washington']
</pre>
<p>&#8230;but if you have names like &#8216;King George III&#8217;, you&#8217;ll have to fix the function to deal with them.</p>
<h3>Example 3</h3>
<p>How about sorting a list of stocks by their maximum closing price for this week?  (Use <span class="c">reverse=True</span> so that highest are listed first)</p>
<pre class="brush: python; title: ; notranslate">
stocks = [ [56, 94, 13, 90, 91], [33, 76, 22, 34, 105], [25, 28, 29, 30, 35] ]
stocks.sort(key=max, reverse=True)

# [[33, 76, 22, 34, 105], [56, 94, 13, 90, 91], [25, 28, 29, 30, 35]]
</pre>
<h3>Example 4</h3>
<p>You can get tricky&#8230;knowing that <span class="c">sort()</span> changes the list in-place, sort individual items by stock price, then sort each stock by its max.</p>
<pre class="brush: python; title: ; notranslate">
def mymax(x):
    x.sort(reverse=True)
    return x[0]

stocks = [ [56, 94, 13, 90, 91], [33, 76, 22, 34, 105], [25, 28, 29, 30, 35] ]
stocks2 = stocks[:] # make a copy, cause we're about to change it

stocks2.sort(key=mymax, reverse=True)

#[[105, 76, 34, 33, 22], [94, 91, 90, 56, 13], [35, 30, 29, 28, 25]]
</pre>
<h3>Example 5</h3>
<p>Or the sort a list by absolute value instead of paying attention to negative signs:</p>
<pre class="brush: python; title: ; notranslate">
deviations = [10, -34, -5, 90, -87]
deviations.sort(key=abs)
# [-5, 10, -34, -87, 90]
</pre>
<p>As you can see, specifying the sort key can be pretty useful if you know it&#8217;s there.  Coming up with these examples really helped me see where this technique would be useful.  You can find more info on sorting on the <a href="http://wiki.python.org/moin/HowTo/Sorting">Python wiki</a>, and <a href="http://http://xahlee.org/perl-python/sort_list.html">comparisons between Python and Perl sorting</a>. </p>
]]></content:encoded>
			<wfw:commentRss>http://scienceoss.com/advanced-sorting-sorting-by-key/feed/</wfw:commentRss>
		<slash:comments>3</slash:comments>
		</item>
	</channel>
</rss>

