Python Exercises

David Stark / Zarkonnen
2 Jun 2012, 10:10 a.m.
A bunch of python exercises centered around reading in data and doing things to it.

Solutions are provided. More "advanced" solutions that do the same thing, generally in fewer lines of code, using a bit more advanced Python features, are also provided. You're not expected to hit on these solutions, but they may be interesting.

General Hints

Longest Name

Problem

The file names.txt contains a list of names, one per line. Write a program that reads in this list and prints the longest name.

Expected Output

Vladimir

References

Solutions

# Reads list of names from file and prints out the longest one.
names_file = open("names.txt", "r") # Open names_file for reading.
longest_name = "" # Any name will be longer than "" when we compare against it.
for l in names_file: # Loop over the lines in the file.
    if len(l) > len(longest_name): # If the line is longer than our current champion...
        longest_name = l # Make it our new longest name.
names_file.close() # Close the file after reading: important housekeeping.
print longest_name # Print out the longest name.
from __future__ import with_statement
with open("names.txt", "r") as f: # This "with statement" takes care of closing the file afterwards.
    print max(f, key=lambda n: len(n)) # Try help(max) for more information.

Sum of Name Lengths

Problem

Write a program that prints the sum of the lengths of the names in names.txt.

Expected Output

38

Hints

When a line is read in from a file in Python, it keeps the new-line character at the end. This means that each line, as read in, is one longer than the name it contains.

Solutions

# Reads list of names from file and prints the sum of the lengths.
names_file = open("names.txt", "r") # Open names_file for reading.
sum_of_lengths = 0
for l in names_file:
    sum_of_lengths = sum_of_lengths + len(l) - 1 # -1 to account for the newline
names_file.close()
print sum_of_lengths
from __future__ import with_statement
with open("names.txt", "r") as f:
    print sum(len(l) - 1 for l in f) # (This is a generator expression!)

Average Name Length

Problem

Write a program that prints the average of the lengths of the names in names.txt.

Expected Output

4.75

Hints

Depending on your version of Python, you may need to turn the number of names in the list into a floating-point number to make sure that when you divide the sum of name lengths by the number of names, you're not using integer division. You do this by using the float function:
5 / 2 -> 2
5 / float(2) -> 2.5

Solutions

# Reads list of names from file and prints the average of their lengths.
names_file = open("names.txt", "r")
sum_of_lengths = 0
number_of_names = 0
for l in names_file:
    sum_of_lengths = sum_of_lengths + len(l) - 1 # -1 to account for the newline
    number_of_names = number_of_names + 1
names_file.close()
print sum_of_lengths / float(number_of_names)
from __future__ import with_statement
# Since it would be so nice to have an "avg" function like a the built-in "min"
# and "max" and so on, let's define it here.
def avg(values, key=lambda x: x):
    summed = 0
    number = 0
    for x in values:
        summed += key(x)
        number += 1
    return summed / float(number)
# (This way we're not keeping all names in memory at the same time.)
with open("names.txt", "r") as f:
    print avg(f, key=lambda n: len(n) - 1)

Shortest Names

Problem

Write a program that prints the shortest names in names.txt, one on each line. There is more than one shortest name, so both need to be printed.

Expected Output

Ed

Jo
Note: The reason there is an empty line between "Ed" and "Jo" is that when you read in lines from a file, you get the lines including the new-line character at the end. print then adds a second new line to this.

References

Solutions

# Reads list of names from file and prints out the shortest ones.
names_file = open("names.txt", "r")
shortest_names = [] # List of shortest names. Right now it's empty.
for l in names_file:
    if len(shortest_names) == 0: # If we have no names at all, any will do.
        shortest_names = [l]
    else:
        # We do have some names in our list currently. Are they the shortest?
        if len(l) < len(shortest_names[0]): # No! This name is shorter!
            shortest_names = [l]
        else:
            if len(l) == len(shortest_names[0]): # This name is the same length.
                shortest_names.append(l) # It gets to join the list.
        # In any other case, the name must be longer than ones in the list.
names_file.close()
# Print the names:
for n in shortest_names:
    print n
# Fun fact: This is actually a worse program in some ways, as it loads the
# entire list of names into memory at once. This can be _very bad_ if there are
# a lot of names.
from __future__ import with_statement
with open("names.txt", "r") as f:
    names = f.readlines()
    names.sort(key=len)
    print "\n".join([n for n in names if len(n) == len(names[0])])

Names to Lengths

Problem

Write a program that reads in the names in names.txt and writes out a file at name_lengths.txt containing the length of each name, one per line, in the corresponding order.

Expected Output (in name_lengths.txt)

4
4
8
7
2
5
6
2

Hints

A new-line character is written as "\n". Converting a number to text is done using the str function. Hence, converting a number x to its string representation ended with a newline is:
str(x) + "\n"
Or, even better, using Python's str.format:
"{0}\n".format(x)
Also, don't forget to subtract 1 from the length of each line read in to account for the newline character at the end.

References

Solutions

# Reads list of names from file and writes a file with their lengths.
names_file = open("names.txt", "r")
lengths_file = open("name_lengths.txt", "w") # Open name_lengths.txt for writing
for l in names_file:
    lengths_file.write(str(len(l) - 1) + "\n")
names_file.close()
lengths_file.close() # Also need to close files after writing to them.
from __future__ import with_statement
with open("names.txt", "r") as f:
    with open("name_lengths.txt", "w") as f2:
        f2.writelines("{0}\n".format(len(l) - 1) for l in f)

Sort Names

Problem

Write a program that reads in the names in names.txt and writes out a file at names_sorted.txt containing them sorted alphabetically.

Expected Output (in names_sorted.txt)

Anna
Ed
Hans
Janice
Jo
Michael
Susan
Vladimir

References

Solutions

# Reads list of names from file and writes them back out, sorted.
names_file = open("names.txt", "r")
sorted_file = open("names_sorted.txt", "w")
names = names_file.readlines()
names.sort()
sorted_file.writelines(names)
names_file.close()
sorted_file.close()
from __future__ import with_statement
with open("names.txt", "r") as f:
    with open("names_sorted.txt", "w") as f2:
        f2.writelines(sorted(f.readlines()))

Sort Names by Length

Problem

Write a program that reads in the names in names.txt and writes out a file at names_sorted_by_length.txt containing them sorted by length.

Expected Output (in names_sorted_by_length.txt)

Ed
Jo
Hans
Anna
Susan
Janice
Michael
Vladimir

References

Solutions

# Reads list of names from file and writes them back out, sorted by length.
names_file = open("names.txt", "r")
sorted_file = open("names_sorted_by_length.txt", "w")
names = names_file.readlines()
names.sort(key=len) # We can use the built-in len function to tell sort to sort by length.
sorted_file.writelines(names)
names_file.close()
sorted_file.close()
from __future__ import with_statement
with open("names.txt", "r") as f:
    with open("names_sorted_by_length.txt", "w") as f2:
        f2.writelines(sorted(f.readlines(), key=len))

Print names of a particular length

Problem

Write a program that reads in the names in names.txt and prints all the names that have the length given by the first command-line argument.

Expected Output (for python names_of_length.py 4)

Hans
Anna

Hints

Converting a string to an integer number is done using the int function.
You can avoid printing a newline by using print x, instead of print x, or you can get a string without its final character (letter) by using x[0:-1].

References

Solutions

# Reads list of names from file and prints out the ones that have the length
# given in the first parameter.
import sys
names_file = open("names.txt", "r")
required_length = int(sys.argv[1]) # The 0th element is the name of the running script.
for l in names_file:
    if len(l) - 1 == required_length:
        print l, # The comma prevents print from adding a newline.
names_file.close()
from __future__ import with_statement
import sys
with open("names.txt", "r") as f:
    print "".join(n for n in f if len(n) - 1 == int(sys.argv[1]))