Skip to content

Commit

Permalink
Break out OOP coding challenge into own NB and misc other clean-ups
Browse files Browse the repository at this point in the history
  • Loading branch information
zstumgoren committed Mar 31, 2024
1 parent 3324f5d commit 308ed3e
Show file tree
Hide file tree
Showing 5 changed files with 273 additions and 200 deletions.
9 changes: 9 additions & 0 deletions content/README.ipynb
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@
" * [Demystifyng Dot Notation](classes_and_oop/README.ipynb)\n",
" * [Modules](classes_and_oop/module_dot_something.ipynb)\n",
" * [The Hidden Life of Objects](classes_and_oop/hidden_life_of_objects.ipynb) - Classes and OOP\n",
" * [Elections OOP Coding Challenge](classes_and_oop/elections_oop_code_challenge.ipynb)\n",
" * [Method chaining](classes_and_oop/method_chaining.ipynb)\n",
" * [Why bother with classes and OOP at all?](classes_and_oop/why_bother.ipynb) - It's a fair question.\n",
"\n",
Expand All @@ -53,6 +54,14 @@
"* [Reshaping Data](pandas_reshaping.ipynb) - Melting \"wide\" data, pivoting \"long\" data\n",
"\n"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "38ec6f4b-5fdc-4c4a-8c2b-adcc3367fa62",
"metadata": {},
"outputs": [],
"source": []
}
],
"metadata": {
Expand Down
251 changes: 251 additions & 0 deletions content/classes_and_oop/elections_oop_code_challenge.ipynb
Original file line number Diff line number Diff line change
@@ -0,0 +1,251 @@
{
"cells": [
{
"cell_type": "markdown",
"id": "5488ca1b-6fe5-42e6-99f9-43828843f5e9",
"metadata": {
"tags": []
},
"source": [
"# Elections OOP Coding challenge\n",
"\n",
"So you now have a basic grounding in [Python classes and OOP](hidden_life_of_objects.ipynb). Let's try to burn this new info into your synapses through a coding challenge.\n",
"\n",
"Below you'll find some toy election data. \n",
"\n",
"We're keeping it simple for now, but many hundreds -- or thousands? millions? -- of lines of code have been written in the real world to manage the complexities of elections. This code has been written by software vendors to help election officials administer local races, along with lowly newsroom coders (including yours truly) to power election night maps and analysis.\n",
"\n",
"The challenges for any given election include:\n",
"\n",
"- Organizing candidates by race (e.g. city council, gubernatorial, U.S. senator, U.S. president)\n",
"- Organizing races by a specific election (e.g. comparing presidential results by state, county, precinct over multiple elections)\n",
"- Tallying votes by candidate to determine winners, ties/runoffs, and other fun edge cases\n",
"\n",
"### The Data\n",
"\n",
"But enough preamble. Here's our extremely simplifed data.\n",
"\n",
"Each row represents the number of votes a presidential candidate received in a particular county.\n",
"\n",
"The data is structured as a list of [dictionaries](../python_dict_basics.ipynb), with each containing the following data points:\n",
"\n",
"- Election `date` and the `office` for the race\n",
"- Candidate `name` and `party`\n",
"- `State` and `County` where each candidate received a specific numvber of `votes`\n",
"\n",
"> Note: This data is *totally* fabricated. And yet you feel the nostalgia for simpler times, no?"
]
},
{
"cell_type": "code",
"execution_count": 1,
"id": "b4557040-ff63-448b-a083-474de0e17748",
"metadata": {},
"outputs": [],
"source": [
"votes = [\n",
" {'date': '2012-11-06', 'office': 'President', 'county': 'Fairfax', 'state': 'VA', 'name': 'Romney', 'party': 'GOP', 'votes': '1000'},\n",
" {'date': '2012-11-06', 'office': 'President', 'county': 'Fairfax', 'state': 'VA', 'name': 'Obama', 'party': 'DEM', 'votes': '2000'},\n",
" {'date': '2012-11-06', 'office': 'President', 'county': 'Shenandoah', 'state': 'VA', 'name': 'Romney', 'party': 'GOP', 'votes': '800'},\n",
" {'date': '2012-11-06', 'office': 'President', 'county': 'Shenandoah', 'state': 'VA', 'name': 'Obama', 'party': 'DEM', 'votes': '800'},\n",
" {'date': '2012-11-06', 'office': 'President', 'county': 'Lee', 'state': 'VA', 'name': 'Romney', 'party': 'GOP', 'votes': '900'},\n",
" {'date': '2012-11-06', 'office': 'President', 'county': 'Lee', 'state': 'VA', 'name': 'Obama', 'party': 'DEM', 'votes': '500'}\n",
"]"
]
},
{
"cell_type": "markdown",
"id": "675b71fc-2f34-484b-b3f6-4935d3f505aa",
"metadata": {},
"source": [
"### Create a Candidate class\n",
"\n",
"For this first part, we're going to provide a bit of starter code. Your task is to:\n",
"\n",
"- Update the `Candidate` class to flesh out the following methods: \n",
" - `add_votes` - add the vote record to the `Candidate.votes` list\n",
" - `total_votes` - tally up and return the total votes based on records stored in `Candidate.votes`\n",
"\n",
"> A bit of advice: Don't try to flesh out both methods at once. Work incrementally. Start with `add_votes`. Create a class instance for a candidate and test the method. Then repeat those steps for `total_votes`."
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "e1fa908a-4406-4d6d-a9e9-6a63062a0494",
"metadata": {},
"outputs": [],
"source": [
"class Candidate:\n",
" \n",
" def __init__(self, candidate_name):\n",
" self.name = candidate_name\n",
" self.votes = [] # An empty list where you can store vote records\n",
" \n",
" def add_votes(self, vote_record):\n",
" # Add code here to add the vote record to self.votes\n",
" pass # NOTE: \"pass\" is a placeholder that does nothing. It's useful to design code before you actually implement the functionality\n",
" \n",
" def total_votes(self):\n",
" # Add code here to tally all votes in self.votes\n",
" # Add code here to *return* the total vote count\n",
" pass"
]
},
{
"cell_type": "markdown",
"id": "db1b0c98-4f9b-48e7-a60e-361557d4860c",
"metadata": {},
"source": [
"Here's a basic roadmap for the steps you should complete (you can use the below code cell and add additional cells as needed).\n",
"\n",
"- Grab the first vote record from `votes` list and store it in a variable.\n",
"- Create a `Candidate` instance using the first vote record that you just stashed in a variable\n",
" - Use the dictionary's `name` key to access the candidate's name\n",
" - Create an instance of the `Candidate` class by supplying the `name` value to the class\n",
" - Save the instance in a new variable called `candidate` (note, that's a lower-case `c`).\n",
"- Call `candidate.name` to verify the name\n"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "c326cf86-648c-451a-b2da-9ab94e52d6f7",
"metadata": {},
"outputs": [],
"source": [
"# Here's some scratch space for you to work"
]
},
{
"cell_type": "markdown",
"id": "0ca6ad28-84c4-4141-8e57-e79e6a8de86b",
"metadata": {
"tags": []
},
"source": [
"### Flesh out add_votes\n",
"\n",
"Next, circle back up to the original `Candidate` class and flesh out the `add_votes` method.\n",
"\n",
"Grab two records from the `votes` list for a single candidate (either Obama or Romney).\n",
"\n",
"Create a `candidate` instance and call `add_votes` twice, once for each vote record.\n",
"\n",
"Inspect `candidate.votes` to verify the records were stored on the instance."
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "bd4b429e-e1b7-49a9-88a2-0990db1974a4",
"metadata": {},
"outputs": [],
"source": [
"# Here's some scratch space to work"
]
},
{
"cell_type": "markdown",
"id": "916410c4-59f1-45de-9d03-ac4c7c686bce",
"metadata": {
"tags": []
},
"source": [
"### Flesh out total_votes\n",
"\n",
"Flesh out the `total_votes` method.\n",
"\n",
"Once again, it's not a bad idea to start small by testing the method on a small number of records for a single candidate.\n",
"\n",
"Repeat the steps from above to create a `Candidate` instance and add a few vote records.\n",
"\n",
"Now call `candidate.total_votes()`.\n",
"\n",
"Did you get the correct result?\n",
"\n",
"\n",
"### Process all the records\n",
"\n",
"With our `Candidate` class now fully fleshed out, you're ready to write the full program. \n",
"\n",
"Remember, the goal is to tally up the votes for both candidates in order to figure out who received the most votes.\n",
"\n",
"For the most part, this is straight-forward and will involve simply looping through the `votes` list and processing each record.\n",
"\n",
"**The one wrinkle is that you'll need a way to store and retrieve a single `candidate` instance for each person in the race.**\n",
"\n",
"A dictionary can be handy for this type of bookkeeping. \n",
"\n",
"For example, let's say you created an empty dictionary called `votes_by_cand = {}`, where the candidate `name` is the key and the `Candidate` instance is the value.\n",
"\n",
"As you loop throug the records, your code can simply:\n",
"- Check `votes_by_cand` to see if the candidate's name is present.\n",
" - If it's not there:\n",
" - Create a `Candidate` instance\n",
" - Call `Candidate.add_votes` with the current record\n",
" - Insert the `Candidate` instance into the dictionary, using `candidate` name as the key and the instance as the value\n",
" - If the candidate *is* in the dictionary, simply call `candidate.add_votes` with the current record\n",
" \n",
"Once you've processed all the records, create one final loop to step through the `votes_by_cand` instances and call their `total_votes()` method.\n",
"\n",
"Now you're ready to answer some news questions:\n",
"\n",
"- How many total votes did each candidate receive?\n",
"- Who won our fictional race?\n",
"- What was the vote count difference?"
]
},
{
"cell_type": "code",
"execution_count": 3,
"id": "3f6ffb95-747e-49b2-b05a-e3a5dd7c2893",
"metadata": {},
"outputs": [],
"source": [
"# Here's some scratch space for you to work"
]
},
{
"cell_type": "markdown",
"id": "58244838-e1e0-4938-8e9e-e52590a3b109",
"metadata": {},
"source": [
"## Summary\n",
"\n",
"Ok, hopefully you're feeling more comfortable with classes and OOP after that bit of practice.\n",
"\n",
"Next up: unraveling the mysteries of [\"method chaining\"](method_chaining.ipynb)."
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "5be35915-220f-43ce-86cd-975d972d2a6b",
"metadata": {},
"outputs": [],
"source": []
}
],
"metadata": {
"kernelspec": {
"display_name": "Python 3 (ipykernel)",
"language": "python",
"name": "python3"
},
"language_info": {
"codemirror_mode": {
"name": "ipython",
"version": 3
},
"file_extension": ".py",
"mimetype": "text/x-python",
"name": "python",
"nbconvert_exporter": "python",
"pygments_lexer": "ipython3",
"version": "3.11.4"
}
},
"nbformat": 4,
"nbformat_minor": 5
}
Loading

0 comments on commit 308ed3e

Please sign in to comment.