<?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; sort</title>
	<atom:link href="http://scienceoss.com/tags/sort/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.1</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>
		<item>
		<title>Sort one list by another list</title>
		<link>http://scienceoss.com/sort-one-list-by-another-list/</link>
		<comments>http://scienceoss.com/sort-one-list-by-another-list/#comments</comments>
		<pubDate>Fri, 11 Apr 2008 14:14:26 +0000</pubDate>
		<dc:creator>ryan</dc:creator>
				<category><![CDATA[NumPy]]></category>
		<category><![CDATA[Python]]></category>
		<category><![CDATA[argsort]]></category>
		<category><![CDATA[sort]]></category>
		<category><![CDATA[sorting]]></category>

		<guid isPermaLink="false">http://scienceoss.com/sort-one-list-by-another-list/</guid>
		<description><![CDATA[Here are a couple of ways of sorting one list by another list in Python. The first uses plain ol&#8217; Python, and the others use NumPy. In each case imagine we want to sort a list of peoples names by their ages. Method 1 Zip the lists together, making sure that the one to sort [...]]]></description>
			<content:encoded><![CDATA[<p>Here are a couple of ways of sorting one list by another list in Python.  The first uses plain ol&#8217; Python, and the others use NumPy.</p>
<p>In each case imagine we want to sort a list of peoples names by their ages.<span id="more-108"></span></p>
<h3>Method 1</h3>
<p>Zip the lists together, making sure that the one to sort by is passed first to zip().  The result is a list of tuples.  When you sort a list of tuples, it sorts using the first item in each tuple.  Then use the zip* trick to unzip the now sorted tuples into separate variables.</p>
<pre class="brush: python; title: ; notranslate">people = ['Jim', 'Pam', 'Micheal', 'Dwight']
ages = [27, 25, 4, 9]

agesAndPeople = zip(ages, people)
agesAndPeople.sort()
sortedAges, sortedPeople = zip(*agesAndPeople)</pre>
<p>Note that if you want to sort in reverse, you can use <span class="c">agesAndPeople.sort(reverse=True)</span>.</p>
<h3>Method 2</h3>
<p>This method uses NumPy, and you don&#8217;t have to convert the lists into arrays.  The argsort() function doesn&#8217;t return the sorted ages . . . instead, it returns the indices that each item would if it were in an already sorted array (try it to see what I mean).  take() is a way of using useful NumPy indexing on a list.  See the next example for something that might be more straigtforward for Matlab users.</p>
<pre class="brush: python; title: ; notranslate">people = ['Jim', 'Pam', 'Micheal', 'Dwight']
ages = [27, 25, 4, 9]

import numpy
inds = numpy.argsort(ages)
sortedPeople = numpy.take(people, inds)</pre>
<h3>Method 3</h3>
<p>This method also uses NumPy, but first it converts the lists into arrays.  Then it uses the argsort() of one to index into the other.</p>
<pre class="brush: python; title: ; notranslate">people = ['Jim', 'Pam', 'Micheal', 'Dwight']
ages = [27, 25, 4, 9]

import numpy
people = numpy.array(people)
ages = numpy.array(ages)
inds = ages.argsort()
sortedPeople = people[inds]</pre>
]]></content:encoded>
			<wfw:commentRss>http://scienceoss.com/sort-one-list-by-another-list/feed/</wfw:commentRss>
		<slash:comments>4</slash:comments>
		</item>
	</channel>
</rss>

