Skip to content
This repository was archived by the owner on Oct 9, 2018. It is now read-only.

Commit f7bdbff

Browse files
author
Maria Mckinley
committed
added solutions for last week
1 parent 2ba4e1b commit f7bdbff

File tree

7 files changed

+823
-0
lines changed

7 files changed

+823
-0
lines changed

solutions/Session08/circle.py

+114
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,114 @@
1+
#!/usr/bin/env python
2+
3+
"""
4+
nifty Circle class
5+
6+
Used to demo propeties and "magic methods"
7+
"""
8+
9+
from math import pi
10+
import functools
11+
12+
13+
# this is a trick to make all the greater than, less than, etc work.
14+
# see: https://docs.python.org/3.6/library/functools.html#functools.total_ordering
15+
@functools.total_ordering
16+
class Circle(object):
17+
"""
18+
simple class to represent a circle
19+
20+
one you can do math with -- a bit odd...
21+
"""
22+
23+
def __init__(self, radius):
24+
self.radius = float(radius)
25+
26+
@classmethod
27+
def from_diameter(cls, diameter):
28+
return cls(diameter / 2.0)
29+
30+
@property
31+
def diameter(self):
32+
return self.radius * 2.0
33+
@diameter.setter
34+
def diameter(self, value):
35+
self.radius = value / 2.0
36+
37+
@property
38+
def area(self):
39+
return self.radius**2 * pi
40+
41+
def __repr__(self):
42+
# usingthe repr attributes is a neat trick
43+
return "Circle({:s})".format(repr(self.radius))
44+
45+
def __str__(self):
46+
return "Circle with radius: {:g}".format(self.radius)
47+
48+
def __add__(self, other):
49+
return Circle(self.radius + other.radius)
50+
51+
def __iadd__(self, other):
52+
"""
53+
for "augmented assignment" -- can be used for in-place addition
54+
55+
Generally used that way for mutable types. This approach returns
56+
self, so that the object is changed in place -- i.e. mutated
57+
"""
58+
self.radius += other.radius
59+
return self
60+
61+
def __mul__(self, factor):
62+
return Circle(self.radius * factor)
63+
64+
def __imul__(self, factor):
65+
"""see __iadd__"""
66+
self.radius *= factor
67+
return self
68+
69+
def __rmul__(self, factor):
70+
return Circle(self.radius * factor)
71+
72+
# You can define them all:
73+
# Might be useful for odd situations (and better performance)
74+
# def __eq__(self, other):
75+
# return self.radius == other.radius
76+
# def __ne__(self, other):
77+
# return self.radius != other.radius
78+
# def __gt__(self, other):
79+
# return self.radius > other.radius
80+
# def __ge__(self, other):
81+
# return self.radius >= other.radius
82+
# def __lt__(self, other):
83+
# return self.radius < other.radius
84+
# def __le__(self, other):
85+
# return self.radius <= other.radius
86+
87+
# Or you can put the @total_ordering decorator on the class definition
88+
# and do only these:
89+
def __eq__(self, other):
90+
return self.radius == other.radius
91+
92+
def __lt__(self, other):
93+
return self.radius < other.radius
94+
95+
96+
# This demostrates how you can
97+
# subclass and get everyhting -- even the alternate constructor!
98+
class Sphere(Circle):
99+
"""
100+
A simple Sphere object, which you can do math with...
101+
"""
102+
103+
def volume(self):
104+
return 4 / 3 * pi * self.radius ** 3
105+
106+
def area(self):
107+
raise NotImplementedError("Spheres don't have an area")
108+
109+
def __repr__(self):
110+
return "Sphere({:g})".format(self.radius)
111+
112+
def __str__(self):
113+
return "Sphere with radius: {:g}".format(self.radius)
114+

solutions/Session08/quad.py

+11
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
2+
class Quadratic:
3+
def __init__(self, a, b, c):
4+
self.a = a
5+
self.b = b
6+
self.c = c
7+
def __call__(self, x):
8+
return self.a * x**2 + self.b * x + self.c
9+
10+
11+
#my_quad = Quadratic(a=2, b=3, c=1)
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,139 @@
1+
2+
"""
3+
example of emulating a sequence using slices
4+
"""
5+
6+
7+
class SparseArray(object):
8+
9+
def __init__(self, my_array=()):
10+
self.length = len(my_array)
11+
self.sparse_array = self._convert_to_sparse(my_array)
12+
13+
def _convert_to_sparse(self, my_array):
14+
sparse_array = {}
15+
for index, number in enumerate(my_array):
16+
if number:
17+
sparse_array[index] = number
18+
return sparse_array
19+
20+
def __len__(self):
21+
return self.length
22+
23+
def __str__(self):
24+
msg = ['SparseArray: [']
25+
for i in range(self.length):
26+
msg.append("{} ".format(self[i]))
27+
msg.append(']')
28+
return "".join(msg)
29+
30+
def __getitem__(self, index):
31+
# this version supports slicing -- far more complicated
32+
mini_array = []
33+
if isinstance(index, slice):
34+
start, stop, step = index.indices(len(self))
35+
if step is None:
36+
step = 1
37+
key = start
38+
mini_array = []
39+
while key < stop:
40+
mini_array.append(self[key])
41+
key += step
42+
return mini_array
43+
else:
44+
# makes it an int, even if it's some other
45+
# type that supports being used as an index
46+
index = index.__index__()
47+
return self._get_single_value(index)
48+
49+
def _get_single_value(self, key):
50+
if key >= self.length:
51+
raise IndexError('array index out of range')
52+
else:
53+
return self.sparse_array.get(key, 0)
54+
55+
def __setitem__(self, index, value):
56+
if isinstance(index, slice):
57+
start, stop, step = index.indices(len(self))
58+
if step is None:
59+
step = 1
60+
key = start
61+
new_values = []
62+
new_keys = []
63+
for each in value:
64+
if key < stop:
65+
self[key] = each
66+
else:
67+
# now instead of replacing values, we need to add (a) value(s) in the center,
68+
# and move stuff over, probably want to collect all of the changes,
69+
# and then make a new dictionary
70+
new_values.append(each)
71+
new_keys.append(key)
72+
key += step
73+
if new_keys:
74+
self._add_in_slice(new_keys, new_values)
75+
else:
76+
index = index.__index__()
77+
self._set_single_value(index, value)
78+
79+
def _set_single_value(self, key, value):
80+
if key > self.length:
81+
raise IndexError('array assignment index out of range')
82+
if value != 0:
83+
self.sparse_array[key] = value
84+
else:
85+
# if the value is being set to zero, we probably need to
86+
# remove a key from our dictionary.
87+
self.sparse_array.pop(key, None)
88+
89+
def _add_in_slice(self, new_keys, new_values):
90+
# sometimes we need to add in extra values
91+
# any existing values
92+
# greater than the last key of the new data
93+
# will be increased by how many
94+
new_dict = {}
95+
slice_length = len(new_keys)
96+
for k, v in self.sparse_array.items():
97+
if k >= new_keys[-1]:
98+
# print('change keys')
99+
# if greater than slice, change key
100+
new_dict[k + slice_length] = v
101+
elif k in new_keys:
102+
# if this is a key we are changing, change it,
103+
# unless we are changing to a zero...
104+
new_value = values[new_keys.index(k)]
105+
if new_value != 0:
106+
new_dict[k] = new_value
107+
else:
108+
new_dict[k] = v
109+
# what if our new key was not previously in the dictionary?
110+
# stick it in now
111+
for k in new_keys:
112+
if k not in new_dict.keys():
113+
new_dict[k] = new_values[new_keys.index(k)]
114+
# note we don't want to do update, since we need to make sure we are
115+
# getting rid of the old keys, when we moved the value to a new key
116+
self.sparse_array = new_dict
117+
# now we need to increase the length by the amount we increased our array by
118+
self.length += slice_length
119+
120+
def __delitem__(self, key):
121+
# we probably need to move the keys if we are not deleting the last
122+
# number, use pop in case it was a zero
123+
if key == self.length - 1:
124+
self.sparse_array.pop(key, None)
125+
else:
126+
# since we need to adjust all of the keys after the one we are
127+
# deleting, probably most efficient to create a new dictionary
128+
new_dict = {}
129+
for k, v in self.sparse_array.items():
130+
if k >= key:
131+
new_dict[k - 1] = v
132+
else:
133+
new_dict[k] = v
134+
# note we don't want to do update, since we need to make sure we are
135+
# getting rid of the old keys, when we moved the value to a new key
136+
self.sparse_array = new_dict
137+
# length is now one shorter
138+
self.length -= 1
139+
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,75 @@
1+
2+
"""
3+
An example of emulating a sequence
4+
5+
A SparseArray is like a list, but only stores the non-zero values
6+
7+
It can be indexed, appended-to, and iterated through.
8+
9+
This version does not support slicing.
10+
"""
11+
12+
13+
class SparseArray(object):
14+
15+
def __init__(self, my_array=()):
16+
"""
17+
initilize a sparse array
18+
19+
:param my_array: an initial sequence to start with
20+
if there are zeros in it, they wil not be stored
21+
"""
22+
self.length = len(my_array)
23+
# self.sparse_array is a dict that stores only the non-zero items
24+
self.sparse_array = self._convert_to_sparse(my_array)
25+
26+
def _convert_to_sparse(self, my_array):
27+
sparse_array = {}
28+
for index, number in enumerate(my_array):
29+
if number: # remember that zeros are falsey.
30+
sparse_array[index] = number
31+
# or the dict comprehension method:
32+
# sparse_array = {index:number for index, number in enumerate(my_array) if number}
33+
return sparse_array
34+
35+
def __len__(self):
36+
return self.length
37+
38+
def __getitem__(self, key):
39+
# fixme: doesn't handle negative indexes properly
40+
try:
41+
return self.sparse_array[key]
42+
except KeyError:
43+
if key >= self.length:
44+
raise IndexError('array index out of range')
45+
return 0
46+
47+
def __setitem__(self, key, value):
48+
if key > self.length:
49+
raise IndexError('array assignment index out of range')
50+
if value != 0:
51+
self.sparse_array[key] = value
52+
else:
53+
# if the value is being set to zero, we probably need to
54+
# remove a key from our dictionary.
55+
self.sparse_array.pop(key, None)
56+
57+
def __delitem__(self, key):
58+
# we probably need to move the keys if we are not deleting the last
59+
# number, use pop in case it was a zero
60+
if key == self.length - 1: # it's the last item -- easy.
61+
self.sparse_array.pop(key, None)
62+
else:
63+
# since we need to adjust all of the keys after the one we are
64+
# deleting, probably most efficient to create a new dictionary
65+
new_dict = {}
66+
for k, v in self.sparse_array.items():
67+
if k >= key:
68+
new_dict[k - 1] = v
69+
else:
70+
new_dict[k] = v
71+
# note we don't want to do update, since we need to make sure we are
72+
# getting rid of the old keys, when we moved the value to a new key
73+
self.sparse_array = new_dict
74+
# length is now one shorter
75+
self.length -= 1

0 commit comments

Comments
 (0)