## 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:

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, -1, ''))
else:
if args == '-max':
max_per_line = int(args)
parse_all_emails(args, max_per_line, '')
else:
permitted_host = args
parse_all_emails(args, -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.
"""

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

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

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

def main(args):
operation = args     # args is calculator.py

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

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