Skip to content

Commit 70501fa

Browse files
committed
ch9
1 parent 268dc9d commit 70501fa

6 files changed

Lines changed: 187 additions & 0 deletions

File tree

Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
# This is the package initialization file for the "counter" package.
2+
3+
from .interface import *
4+
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
# This module implements the public interface to the "counter" package.
2+
3+
def reset():
4+
""" Reset our counter.
5+
6+
This should be called before we start counting.
7+
"""
8+
global _counts
9+
_counts = {} # Maps value to number of occurrences.
10+
11+
12+
def add(value):
13+
""" Add the given value to our counter.
14+
"""
15+
global _counts
16+
17+
try:
18+
_counts[value] += 1
19+
except KeyError:
20+
_counts[value] = 1
21+
22+
23+
def totals():
24+
""" Return the number of times each value has occurred.
25+
26+
We return a list of (value, num_occurrences) tuples, one
27+
for each unique value included in the count.
28+
"""
29+
global _counts
30+
31+
results = []
32+
for value in sorted(_counts.keys()):
33+
results.append((value, _counts[value]))
34+
return results
35+
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
# This module implements various unit tests for the ``counter`` package.
2+
3+
import unittest
4+
5+
import counter
6+
7+
class CounterTestCase(unittest.TestCase):
8+
""" Unit tests for the ``counter`` package.
9+
"""
10+
def test_counter_totals(self):
11+
counter.reset()
12+
counter.add(1)
13+
counter.add(2)
14+
counter.add(3)
15+
counter.add(1)
16+
self.assertEqual(counter.totals(), [(1, 2), (2, 1), (3, 1)])
17+
18+
def test_counter_reset(self):
19+
counter.reset()
20+
counter.add(1)
21+
counter.reset()
22+
counter.add(2)
23+
self.assertEqual(counter.totals(), [(2, 1)])
24+
25+
26+
if __name__ == "__main__":
27+
unittest.main()
28+
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
# This is the package initialization file for the "counter" package.
2+
3+
from .interface import *
4+
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,68 @@
1+
# This module implements the public interface to the "counter" package.
2+
3+
def reset(ranges=None):
4+
""" Reset our counter.
5+
6+
If 'ranges' is supplied, the given list of values will be used as the
7+
start and end of each range of values. In this case, the totals will
8+
be calculated based on a range of values rather than individual values.
9+
10+
This should be called before we start counting.
11+
"""
12+
global _ranges
13+
global _counts
14+
15+
_ranges = ranges
16+
_counts = {} # If _ranges is None, maps value to number of occurrences.
17+
# Otherwise, maps (min_value,max_value) to number of
18+
# occurrences.
19+
20+
21+
def add(value):
22+
""" Add the given value to our counter.
23+
"""
24+
global _ranges
25+
global _counts
26+
27+
if _ranges == None:
28+
key = value
29+
else:
30+
key = None
31+
for i in range(len(_ranges)-1):
32+
if value >= _ranges[i] and value < _ranges[i+1]:
33+
key = (_ranges[i], _ranges[i+1])
34+
break
35+
if key == None:
36+
raise RuntimeError("Value out of range: {}".format(value))
37+
38+
try:
39+
_counts[key] += 1
40+
except KeyError:
41+
_counts[key] = 1
42+
43+
44+
def totals():
45+
""" Return the number of times each value has occurred.
46+
47+
If we are currently counting ranges of values, we return a list of
48+
(min_value, max_value, num_occurrences) tuples, one for each range.
49+
Otherwise, we return a list of (value, num_occurrences) tuples, one for
50+
each unique value included in the count.
51+
"""
52+
global _ranges
53+
global _counts
54+
55+
if _ranges != None:
56+
results = []
57+
for i in range(len(_ranges)-1):
58+
min_value = _ranges[i]
59+
max_value = _ranges[i+1]
60+
num_occurrences = _counts.get((min_value, max_value), 0)
61+
results.append((min_value, max_value, num_occurrences))
62+
return results
63+
else:
64+
results = []
65+
for value in sorted(_counts.keys()):
66+
results.append((value, _counts[value]))
67+
return results
68+
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
# This module implements various unit tests for the ``counter`` package.
2+
3+
import unittest
4+
5+
import counter
6+
7+
class CounterTestCase(unittest.TestCase):
8+
""" Unit tests for the ``counter`` package.
9+
"""
10+
def test_counter_totals(self):
11+
counter.reset()
12+
counter.add(1)
13+
counter.add(2)
14+
counter.add(3)
15+
counter.add(1)
16+
self.assertEqual(counter.totals(), [(1, 2), (2, 1), (3, 1)])
17+
18+
def test_counter_reset(self):
19+
counter.reset()
20+
counter.add(1)
21+
counter.reset()
22+
counter.add(2)
23+
self.assertEqual(counter.totals(), [(2, 1)])
24+
25+
26+
class RangeCounterTestCase(unittest.TestCase):
27+
""" Unit tests for the range-based features of ``counter`` package.
28+
"""
29+
def test_range_totals(self):
30+
counter.reset([0, 5, 10, 15])
31+
counter.add(3)
32+
counter.add(9)
33+
counter.add(4.5)
34+
counter.add(12)
35+
counter.add(14.2)
36+
counter.add(8)
37+
self.assertEqual(counter.totals(),
38+
[(0, 5, 2), (5, 10, 2), (10, 15, 2)])
39+
40+
def test_out_of_range(self):
41+
counter.reset([0, 5, 10, 15])
42+
with self.assertRaises(RuntimeError):
43+
counter.add(19.1)
44+
45+
46+
if __name__ == "__main__":
47+
unittest.main()
48+

0 commit comments

Comments
 (0)