Assignment 06

Solutions to Assignment 06.

Reverse Lines

Write a program reverse.py that takes a filename as command-line argument and prints all the lines in that file in the reverse order.

$ cat files/five.txt
one
two
three
four
five

$ python reverse.py files/five.txt
five
four
three
two
one

Solution

import sys

filename = sys.argv[1]

lines = open(filename).readlines()[::-1]
for line in lines:
    print(line, end="")

Generate Password

Write a function generate_password to generate random password of given length.

The function should take length n as argument and generate a password using mix of letters from lowercase, uppercase from English alphabet and digits. It should not have any other characters.

>>> generate_password(8)
'rBZLcP8V'
>>> generate_password(25)
'JU938tUT36QRvVEPh9OLrxlrB'

Hint

  • See random.choice function from the random module
  • See string.ascii_letters and string.digits from the string module

Solution

import string
import random

def generate_password(n):
    text = string.ascii_letters + string.digits
    return "".join([random.choice(text) for i in range(n)])

Weekly Average

Daily average prices of some symbols are given each for five days of a week. Data consists of list of records for each day. Every record consists of (symbol, day, stock price). Write a function weekly_average to compute weekly average for given symbol using this data. it should work as given below

>>> prices = [('IBM', 'Monday', 111.71436961893693),
              ('IBM', 'Tuesday', 141.21220022208635),
              ('IBM', 'Wednesday', 112.40571010053796),
              ('IBM', 'Thursday', 137.54133351926248),
              ('IBM', 'Friday', 140.25154281801224),
              ('MICROSOFT', 'Monday', 235.0403622499107),
              ('MICROSOFT', 'Tuesday', 225.0206535036475),
              ('MICROSOFT', 'Wednesday', 216.10342426936444),
              ('MICROSOFT', 'Thursday', 200.38038844494193),
              ('MICROSOFT', 'Friday', 235.80850482793264),
              ('APPLE', 'Monday', 321.49182055844256),
              ('APPLE', 'Tuesday', 340.63612771662815),
              ('APPLE', 'Wednesday', 303.9065277507285),
              ('APPLE', 'Thursday', 338.1350605764038),
              ('APPLE', 'Friday', 318.3912296144338)]
>>> weekly_average(prices, "APPLE")
324.51215324332736

Solution

def weekly_average(prices, symbol):
    values = [price for sym, day, price in prices if sym == symbol]
    return sum(values)/len(values)

Sort Command

Write a program sort.py that takes filename as a command-line argument and prints lines in that file in the sorted order.

This program should support the following flags.

-i --ignore-case    ignore the case while sorting
-n --numeric-sort   compare according to string numerical value
-r --reverse        print the results in the reverse order
$ python sort.py files/sort/names.txt
alice
bob
charlie
dave

$ python sort.py -r files/sort/names.txt
dave
charlie
bob
alice

$ python sort.py files/sort/names-with-case.txt
Alice
Dave
bob
charlie

$ python sort.py -i files/sort/names-with-case.txt
Alice
Dave
bob
charlie

$ python sort.py files/sort/numbers.txt
1
10
100
1000
2
20
200
2000

$ python sort.py -n files/sort/numbers.txt
1
2
10
20
100
200
1000
2000

$ python sort.py -nr files/sort/numbers.txt
2000
1000
200
100
20
10
2
1

Hint: use argparse

Solution

import argparse

p = argparse.ArgumentParser()
p.add_argument("-i", "--ignore-case", action="store_true", default=False, help="ignore case")
p.add_argument("-n", "--numeric-sort", action="store_true", default=False, help="numeric sort")
p.add_argument("-r", "--reverse", action="store_true", default=False, help="reverse order")
p.add_argument("filename")
args = p.parse_args()

def get_key(args):
    if args.numeric_sort:
        return int
    elif args.ignore_case:
        return str.lower
    else:
        return None

key = get_key(args)
reverse = args.reverse
lines = sorted(open(args.filename), key=key, reverse=reverse)
for line in lines:
    print(line, end="")

Hosts Writer

Write a module hosts with two functions tostring and write to serialize a dictionary with hosts to IP address mapping.

The tostring function takes a dictionary with host to ip mapping to a string in /etc/hosts file format.

The write function takes a filename and a dictionary as arguments and writes the dictionary in /etc/hosts file format to the specified file.

>>> import hosts
>>> data = {"web": "1.2.3.4", "db": "1.2.3.5"}
>>> print(hosts.tostring(data))
1.2.3.4 web
1.2.3.5 db

>>> data = {"web1": "1.2.3.4", "web2": "1.2.3.4", "db": "1.2.3.5"}
>>> print(hosts.tostring(data))
1.2.3.4 web1 web2
1.2.3.5 db

>>> hosts.write("hosts.txt", data)
>>> print(open("hosts.txt").read())
1.2.3.4 web1 web2
1.2.3.5 db

Also write a test_hosts.py with test cases to verify if your solution is correct.

Solution

# hosts.py

def tostring(hosts):
    ips = {}
    for host, ip in hosts:
        ips.setdefault(ip, []).append(host)

    lines = [" ".join([ip] + names) for ip, names in ips.items()]
    return "\n".join(lines)

def write(filename, hosts):
    with open(filename, "w") as f:
        f.write(tostring(hosts))