Range & Loop Problems

          
def negative(n):
    nums = []
    for i in range(n, (-1 * n) - 1, -1):
        nums.append(i)
    return nums
    # Note: unary - has the highest precedence, so the 2nd param
    # can be written as -n - 1, but the parenthesis look fine too.


def threes(n):
    outer = []
    # first = first num of inner 1, 2, ... n
    for first in range(1, n + 1):
        inner = []
        for i in range(first, first + 3):
            inner.append(i)
        outer.append(inner)
    return outer


def countdown(n):
    outer = []
    # count = count of numbers in inner list
    for count in range(1, n + 1):
        inner = []
        for i in range(10, 10 - count, -1):
            inner.append(i)
        outer.append(inner)
    return outer
          
        

Finding the smallest unique positive integer

          
def smallest_uniq_pos_int(filename):

    all_positive_nums = []
    seen_before = []
    not_unique = []

    with open(filename, 'r') as f:
        for line in f:
        num = int(line)
        if num >= 1:
            all_positive_nums.append(num)
            if num in seen_before:
                not_unique.append(num)
            else:
                seen_before.append(num)

    smallest = 0
    for num in all_positive_nums:
        if num not in not_unique and (num < smallest or smallest == 0):
            smallest = num 

    return smallest          
          
        

String Parsing

Introduction to String Parsing

              
def exclaim(s):
    mark = s.find('!')
    if mark == -1:
        return ''
    # scan left from the exclamation mark
    i = mark - 1
    while i >= 0 and s[i].isalpha():
        i -= 1
    word = s[i + 1: mark + 1]
    if len(word) >= 2:
        return word
    return ''

def vowels(s):
    colon = s.find(':')
    if colon == -1:
        return ''
    # scan right from the colon
    i = colon + 1
    while i < len(s) and s[i].lower() in 'aeiou':
        i += 1
    word = s[colon + 1:i]
    return word
              
          

Extracting Email Hostnames

This is one possible approach to decomposing this problem. Think about other ways to structure your solution!

              
def extract_hostname(line):
    at_index = line.find('@')
    if at_index == -1:
        return ''
    # scan forward till the end of the word or line
    i = at_index + 1
    while i < len(line) and line[i] != ' ':
        if line[i].isalpha() or line[i] =='.':
            i += 1
        else:
            break # end the loop immediately - we'll talk about this more next week!

    hostname = line[at_index + 1: i]

    if len(hostname) < 4 or not '.' in hostname:
        return ''

    return hostname

def extract_all_hostnames(filename):
    hostnames = []
    with open(filename, 'r') as f:
        for line in f:
            hostname = extract_hostname(line)
            if hostname != '' and not hostname in hostnames:
                hostnames.append(hostname)
    hostnames = sorted(hostnames)
    return hostnames
              
          

A much better email parser

This is the solution to parts 1 and 2 of this problem.

          
import sys

def is_email_char(ch):
    return ch.isalnum() or ch in ['.', '-', '_']

def parse_emails(s, max_per_line, permitted_host):
    emails = []
    search = 0
    while (max_per_line == -1 or len(emails) < max_per_line) and search < len(s):
        at = s.find('@', search)
        if at == -1:
            break

        start = at - 1
        while start >= 0 and is_email_char(s[start]):
            start -= 1
        end = at + 1
        while end < len(s) and is_email_char(s[end]):
            end += 1
        host = s[at+1:end]

        if permitted_host == '' or host == permitted_host:
            email = s[start+1:end]
            if host.find(".") != -1 and at - start > 0:
                emails.append(email)
        search = end

    return sorted(emails)

def parse_all_emails(filename, max_per_line, permitted_host):
    parsed = []
    with open(filename, 'r') as f:
        for line in f:
            parsed.extend(parse_emails(line, max_per_line, permitted_host))
    return parsed

def main():
    args = sys.argv[1:]
    if len(args) == 1:
        print(parse_all_emails(args[0], -1, ''))
    else:
        if args[0] == '-max':
            max_per_line = int(args[1])
            parse_all_emails(args[2], max_per_line, '')
        else:
            permitted_host = args[1]
            parse_all_emails(args[2], -1, permitted_host)

if __name__ == "__main__":
    main()
          
        

The main function

This is one possible approach to decomposing this problem. Think about other ways to structure your solution!

            
"""
calculator.py
-------------
Implements the calculator program, as specified in the
section 4 handout.
"""

import sys # so we have access to argv

def exp(base, power):
    total = 1
    for i in range(power):
        total *= base
    return total

def square(base):
    return exp(base, 2)

def add(args):
    total = 0
    for i in range(len(args) - 2):
        total += int(args[i + 2])
    return total

def main(args):
    operation = args[1]     # args[0] is calculator.py

    if operation == "-exp":
        base = int(args[2]) # convert the argument to an int
        power = int(args[3])
        result = exp(base, power)
        print(result)

    if operation == "-square":
        base = int(args[2])
        result = square(base)
        print(result)

    if operation == "-add":
        result = add(args)
        print(results)

if __name__ == "__main__":
    main(sys.argv)