Skip to content

Commit 1625a07

Browse files
JFincher42martin-martinbrendawelesbzaczynski
authored
Skip-ahead-with-continue initial code checkin (#663)
* Initial code checkin after linting * Update project code Add pyproject.toml, Add named scripts, Rename script, Remove initial versions of scripts * Update README.md * Update aoc_2022_d7.py * Post final QA fixes --------- Co-authored-by: martin-martin <[email protected]> Co-authored-by: Martin Breuss <[email protected]> Co-authored-by: brendaweles <[email protected]> Co-authored-by: Bartosz Zaczyński <[email protected]>
1 parent 1666e7b commit 1625a07

File tree

6 files changed

+219
-0
lines changed

6 files changed

+219
-0
lines changed

python-continue/README.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
# Skip Ahead in Loops With Python's Continue Keyword
2+
3+
This folder provides the code examples for the Real Python tutorial [Skip Ahead in Loops With Python's Continue Keyword](https://realpython.com/python-continue/).

python-continue/aoc_2022_d7.py

Lines changed: 166 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,166 @@
1+
# AOC 2022 Day 07
2+
3+
import pathlib
4+
5+
root_path = pathlib.Path.home() / "git" / "AOC2022" / "day07" / "day07"
6+
7+
8+
def get_path_name(folder_name):
9+
if len(folder_name) > 1:
10+
return "/".join(folder_name)[1:]
11+
else:
12+
return "/".join(folder_name)
13+
14+
15+
def parse(lines):
16+
17+
# We read each line and create some structures
18+
# - We maintain a path list stack, which tells us how deep the structure is
19+
# - It starts with ["/"]
20+
# - We can do a "/".join(path)[1:] to get the full path, and drop the "/"
21+
# - We maintain a dictionary of paths to files
22+
# - The key is the full path
23+
# - The value is a list of tuples
24+
# - Each tuple contains the name and file size
25+
#
26+
# Here's the plan when we get to each line
27+
# - if it's a cd command
28+
# - If it's a directory name, we push that onto the end of the path list
29+
# - If it's a .., we pop the last item off the path list
30+
# - if it's an ls command, or a dir <name>
31+
# - skip to the next line
32+
# - if it's a number and file
33+
# - construct the tuple (file, size)
34+
# - Get the full path with the code above
35+
# - Is this path in the dictionary?
36+
# - If not, create it with a blank list
37+
# - Append the tuple to the path list
38+
39+
# Where do we keep the folder names
40+
folder_name = ["/"]
41+
42+
# Where do we keep the files and sizes
43+
folder_files = {}
44+
45+
# Start reading at the second line - we know the first two line
46+
for line in lines[2:]:
47+
# Split the line so we can parse it
48+
part = line.split()
49+
50+
# What kind of line is it?
51+
# Are we changing into a folder
52+
if part[1] == "ls":
53+
# We can skip these lines
54+
continue
55+
56+
# Is it a folder? We need to ready for it
57+
if part[0] == "dir":
58+
# Get the current path, and append this path to it
59+
path = get_path_name(folder_name)
60+
if path.endswith("/"):
61+
path += part[1]
62+
else:
63+
path += "/" + part[1]
64+
65+
# Add a blank to the dictionary
66+
# If we don't do this, we miss empty folders in our output
67+
# They may contribute to the answer later.
68+
folder_files[path] = []
69+
70+
# Keep going
71+
continue
72+
73+
# Are we changing folders
74+
if part[1] == "cd":
75+
# Backing up? Remove this folder
76+
if part[2] == "..":
77+
folder_name.pop()
78+
# Heading down? Add this folder
79+
else:
80+
folder_name.append(part[2])
81+
82+
else:
83+
# It's a file, so we need the full path
84+
path = get_path_name(folder_name)
85+
86+
if path not in folder_files.keys():
87+
folder_files[path] = []
88+
89+
# Append this tuple to that list
90+
folder_files[path].append((part[1], int(part[0])))
91+
92+
# We're done, return the dictionary
93+
return folder_files
94+
95+
96+
def get_file_sizes(tree):
97+
98+
# We've got the tree, so we need all the keys
99+
paths = sorted([k for k in tree.keys()], reverse=True)
100+
101+
# We need a dictionary to store the file sizes for each path
102+
files_sizes = {}
103+
104+
# And a place for the total
105+
for current_path in paths:
106+
for containing_path in tree.keys():
107+
if containing_path.startswith(current_path):
108+
# Do we have a current path
109+
if current_path not in files_sizes.keys():
110+
files_sizes[current_path] = 0
111+
112+
# Add the files in this folder
113+
for _, size in tree[containing_path]:
114+
files_sizes[current_path] += size
115+
116+
# print(f"Checking {check_path}... {current_path} is in it")
117+
118+
# DEBUG: Print the files sizes
119+
# for k, v in files_sizes.items():
120+
# print(f"Folder {k} contains {v} bytes of files")
121+
return files_sizes
122+
123+
124+
def part1(file_sizes):
125+
126+
total = 0
127+
128+
# Now we can go through them all in this order
129+
for _, total_size in file_sizes.items():
130+
if total_size <= 100_000:
131+
total += total_size
132+
133+
return total
134+
135+
136+
def part2(file_sizes):
137+
# How much free space do we have?
138+
free_space = 70_000_000 - file_sizes["/"]
139+
140+
# How much more do we need?
141+
needed_space = 30_000_000 - free_space
142+
143+
# Let's find the one folder which gets us to enough free space
144+
space = 70_000_000
145+
for _, proposed in file_sizes.items():
146+
# Not enough space?
147+
if proposed < needed_space:
148+
continue
149+
150+
# Found one, let's make sure it's the smallest
151+
space = min(space, proposed)
152+
153+
return space
154+
155+
156+
if __name__ == "__main__":
157+
158+
with open(root_path / "input", "r") as f:
159+
# with open(root_path / "sample", "r") as f:
160+
lines = [line.strip() for line in f.readlines()]
161+
162+
tree = parse(lines)
163+
file_sizes = get_file_sizes(tree)
164+
165+
print(f"Part 1: Answer: {part1(file_sizes)}")
166+
print(f"Part 2: Answer: {part2(file_sizes)}")

python-continue/code_disassembly.py

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
import instaviz
2+
3+
4+
def add_numbers():
5+
total = 0
6+
7+
for number in range(-10, 10):
8+
if number < 0:
9+
continue
10+
total += number
11+
12+
return total
13+
14+
15+
instaviz.show(add_numbers)

python-continue/continue_finally.py

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
for number in range(2):
2+
try:
3+
print(f"Iteration {number}: start of try block")
4+
5+
if number == 1:
6+
print(f" Executing `continue` in iteration {number}...")
7+
continue
8+
9+
print(f" Normal flow in iteration {number}...")
10+
11+
except Exception as e:
12+
print(f"Iteration {number}: Exception: {e}")
13+
14+
finally:
15+
print(f"Iteration {number}: finally block")
16+
17+
print(f"Iteration {number}: rest of loop body", end="\n\n")

python-continue/pyproject.toml

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
[project]
2+
name = "python-continue"
3+
version = "0.1.0"
4+
description = "Code for the Real Python tutorial on Python's `continue` keyword"
5+
readme = "README.md"
6+
requires-python = ">=3.9"
7+
dependencies = ["instaviz"]

python-continue/sum_whole_numbers.py

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
print("Enter one whole number per input.")
2+
print("Type 0 to stop and display their sum:")
3+
4+
total = 0
5+
6+
while (user_int := int(input("+ "))) != 0:
7+
if user_int < 0:
8+
continue
9+
total += user_int
10+
11+
print(f"{total=}")

0 commit comments

Comments
 (0)