-
Notifications
You must be signed in to change notification settings - Fork 0
/
database.py
129 lines (98 loc) · 4.89 KB
/
database.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
"""A database of near-Earth objects and their close approaches.
A `NEODatabase` holds an interconnected data set of NEOs and close approaches.
It provides methods to fetch an NEO by primary designation or by name, as well
as a method to query the set of close approaches that match a collection of
user-specified criteria.
Under normal circumstances, the main module creates one NEODatabase from the
data on NEOs and close approaches extracted by `extract.load_neos` and
`extract.load_approaches`.
You'll edit this file in Tasks 2 and 3.
"""
class NEODatabase:
"""A database of near-Earth objects and their close approaches.
A `NEODatabase` contains a collection of NEOs and a collection of close
approaches. It additionally maintains a few auxiliary data structures to
help fetch NEOs by primary designation or by name and to help speed up
querying for close approaches that match criteria.
"""
def __init__(self, neos, approaches):
"""Create a new `NEODatabase`.
As a precondition, this constructor assumes that the collections of
NEOs and close approaches haven't yet been linked - that is, the
`.approaches` attribute of each `NearEarthObject` resolves to an empty
collection, and the `.neo` attribute of each `CloseApproach` is None.
However, each `CloseApproach` has an attribute (`._designation`) that
matches the `.designation` attribute of the corresponding NEO. This
constructor modifies the supplied NEOs and close approaches to link
them together - after it's done, the `.approaches` attribute of each
NEO has a collection of that NEO's close approaches, and the `.neo`
attribute of each close approach references the appropriate NEO.
:param neos: A collection of `NearEarthObject`s.
:param approaches: A collection of `CloseApproach`es.
"""
self._neos = neos
self._approaches = approaches
self._neos_lookup = dict()
for index, neo in enumerate(self._neos):
self._neos_lookup[neo.designation] = index
self._cas_lookup = dict()
for ca in self._approaches:
if self._cas_lookup.get(ca._designation) is not None:
self._cas_lookup[ca._designation].append(ca)
else:
self._cas_lookup[ca._designation] = [ca]
for key in self._neos_lookup.keys():
key_value = self._cas_lookup.get(key)
if key_value is not None:
self._neos[self._neos_lookup[key]].approaches = key_value
for key, values in self._cas_lookup.items():
if self._neos_lookup.get(key) is not None:
neo = self._neos[self._neos_lookup.get(key)]
for ca in values:
ca.neo = neo
def get_neo_by_designation(self, designation):
"""Find and return an NEO by its primary designation.
If no match is found, return `None` instead.
Each NEO in the data set has a unique primary designation, as a string.
The matching is exact - check for spelling and capitalization if no
match is found.
:param designation: The primary designation of the NEO to search for.
:return: The `NearEarthObject` with the desired primary designation,
or `None`.
"""
if self._neos_lookup.get(designation) is not None:
return self._neos[self._neos_lookup.get(designation)]
else:
return None
def get_neo_by_name(self, name):
"""Find and return an NEO by its name.
If no match is found, return `None` instead.
Not every NEO in the data set has a name. No NEOs are associated with
the empty string nor with the `None` singleton.
The matching is exact - check for spelling and capitalization if no
match is found.
:param name: The name, as a string, of the NEO to search for.
:return: The `NearEarthObject` with the desired name, or `None`.
"""
for neo in self._neos:
if neo.name == name:
return neo
return None
def query(self, filters=()):
"""Query close approaches to build list that match a group of filters.
This generates a stream of `CloseApproach` objects that match all of
the provided filters.
If no arguments are provided, generate all known close approaches.
The `CloseApproach` objects are generated in internal order, which
isn't guaranteed to be sorted meaningfully, although is often sorted by
time.
:param filters: A collection of filters capturing user-specified
criteria.
:return: A stream of matching `CloseApproach` objects.
"""
for approach in self._approaches:
result = True
for filter in filters:
result &= filter(approach)
if result:
yield approach