''' weatherstats.py Ben Cochran This is my implementation of the weather stats assignment. ''' from __future__ import with_statement import sys, math def standardDeviation(listOfNumbers): '''Returns the standard deviation of the specified list of numbers if the list contains 2 or more elements. Otherwise, returns 0. This function assumes that its parameter refers to a (possibly empty) list of numbers.''' if len(listOfNumbers) == 0: return 0 theMean = mean(listOfNumbers) # Here I'm using map() and lambda to square each item in the list this # could also be done with list comprehension, but this was a nice time to # include lambda notation listOfNumbers = map(lambda x: (x-theMean) ** 2, listOfNumbers) # so, alternatively: # listOfNumbers = [(x-theMean) ** 2 for x in listOfNumbers] return math.sqrt(sum(listOfNumbers) / float(len(listOfNumbers))) def mean(listOfNumbers): '''Returns the mean of the specified list of numbers if the list contains at least one element. Otherwise, returns 0. This function assumes that its parameter refers to a (possibly empty) list of numbers.''' if len(listOfNumbers) == 0: return 0 return sum(listOfNumbers) / float(len(listOfNumbers)) def loadWeatherData(fileName): '''Loads temperature data from the specified file into a list of lists of integers, and returns the list. This function assumes that each line of the file consists of a year followed by some number of temperatures, all separated by commas. For example, if the file looks like this: 1939,-10,5,3,14,... 1940,2,8,-1,4,... ... 2008,7,12,3,5,-2,... (which means that on Jan 1, 1939, the high temperature was 10, etc.), then loadWeatherData will return a list of lists like this: [[1939,-10,5,3,14,...], [1940,2,...], ..., [2008,7,12,...]] ''' # using a `with` statement to handle closing the file for me. # see: http://effbot.org/zone/python-with-statement.htm with open(fileName) as f: # this is an example of something called list comprehension # for more info see: http://docs.python.org/tutorial/datastructures.html#list-comprehensions return [[int(c) for c in line.split(',')] for line in f] def main(args): '''Reads in the arguments, loads the data, computes the various values, and prints a nice little report of the findings ''' if len(args) != 2: return 'usage: python %s weather_file' % args[0] filename = args[1] data = loadWeatherData(filename) # I'm storing highest/lowest as tuples of (value, year) and using the float # value of "infinity" and "-infinity" for initial values. This keeps me # from needing to special-case my initial values or comparisons highestMean = (float('-infinity'), None) lowestMean = (float('infinity'), None) highestStdDev = (float('-infinity'), None) lowestStdDev = (float('infinity'), None) highestTemp = (float('-infinity'), None) lowestTemp = (float('infinity'), None) print "High temperature data (Fahrenheit)" print print "Year Mean Std Dev" for yearData in data: year = yearData[0] temps = yearData[1:] theMean = mean(temps) stdDev = standardDeviation(temps) highest = max(temps) lowest = min(temps) print "%s%10.2f%10.2f" % (year, theMean, stdDev) # Track the highest/lowest values as we go along. This isn't the best # example of separating business-logic from display-logic, but for this # application, I'm willing to let it slide. if theMean > highestMean[0]: highestMean = (theMean, year) if theMean < lowestMean[0]: lowestMean = (theMean, year) if stdDev > highestStdDev[0]: highestStdDev = (stdDev, year) if stdDev < lowestStdDev[0]: lowestStdDev = (stdDev, year) if highest > highestTemp[0]: highestTemp = (highest, year) if lowest < lowestTemp[0]: lowestTemp = (lowest, year) print # Notice that I don't use `% (highestMean[0], highestMean[1])` because # highestMean itself is a tuple that looks exactly like that... and Python # knows what to do with it print 'Highest mean temperature: %.2f (%s)' % highestMean print 'Lowest mean temperature: %.2f (%s)' % lowestMean print 'Highest standard deviation: %.2f (%s)' % highestStdDev print 'Lowest standard deviation: %.2f (%s)' % lowestStdDev print 'Highest temperature: %.2f (%s)' % highestTemp print 'Lowest temperature: %.2f (%s)' % lowestTemp if __name__ == '__main__': sys.exit(main(sys.argv))