diff --git a/skip-ahead-with-continue/README.md b/skip-ahead-with-continue/README.md new file mode 100644 index 0000000000..a93ce54f64 --- /dev/null +++ b/skip-ahead-with-continue/README.md @@ -0,0 +1,3 @@ +# Skip Ahead with Continue + +This folder provides the code examples for the Real Python tutorial [Skip Ahead with `continue`](https://realpython.com/skip-ahead-with-continue/). diff --git a/skip-ahead-with-continue/aoc_2022_d7.py b/skip-ahead-with-continue/aoc_2022_d7.py new file mode 100644 index 0000000000..7e3990a4de --- /dev/null +++ b/skip-ahead-with-continue/aoc_2022_d7.py @@ -0,0 +1,166 @@ +# AOC 2022 Day 07 + +import pathlib + +root_path = pathlib.Path.home() / "git" / "AOC2022" / "day07" / "day07" + + +def get_path_name(folder_name): + if len(folder_name) > 1: + return "/".join(folder_name)[1:] + else: + return "/".join(folder_name) + + +def parse(lines): + + # We read each line and create some structures + # - We maintain a path list stack, which tells us how deep the structure is + # - It starts with ["/"] + # - We can do a "/".join(path)[1:] to get the full path, and drop the "/" + # - We maintain a dictionary of paths to files + # - The key is the full path + # - The value is a list of tuples. + # - Each tuple contains the name and file size + # + # Here's the plan when we get to each line. + # - if it's a cd command + # - If it's a directory name, we push that onto the end of the path list + # - If it's a .., we pop the last item off the path list + # - if it's an ls command, or a dir + # - skip to the next line + # - if it's a number and file + # - construct the tuple (file, size) + # - Get the full path with the code above + # - Is this path in the dictionary? + # - If not, create it with a blank list + # - Append the tuple to the path list + + # Where do we keep the folder names + folder_name = ["/"] + + # Where do we keep the files and sizes + folder_files = {} + + # Start reading at the second line - we know the first two line + for line in lines[2:]: + # Split the line so we can parse it + part = line.split() + + # What kind of line is it? + # Are we changing into a folder + if part[1] == "ls": + # We can skip these lines + continue + + # Is it a folder? We need to ready for it + if part[0] == "dir": + # Get the current path, and append this path to it + path = get_path_name(folder_name) + if path.endswith("/"): + path += part[1] + else: + path += "/" + part[1] + + # Add a blank to the dictionary + # If we don't do this, we miss empty folders in our output + # They may contribute to the answer later. + folder_files[path] = [] + + # Keep going + continue + + # Are we changing folders + if part[1] == "cd": + # Backing up? Remove this folder + if part[2] == "..": + folder_name.pop() + # Heading down? Add this folder + else: + folder_name.append(part[2]) + + else: + # It's a file, so we need the full path + path = get_path_name(folder_name) + + if path not in folder_files.keys(): + folder_files[path] = [] + + # Append this tuple to that list + folder_files[path].append((part[1], int(part[0]))) + + # We're done, return the dictionary + return folder_files + + +def get_file_sizes(tree): + + # We've got the tree, so we need all the keys + paths = sorted([k for k in tree.keys()], reverse=True) + + # We need a dictionary to store the file sizes for each path + files_sizes = {} + + # And a place for the total + for current_path in paths: + for containing_path in tree.keys(): + if containing_path.startswith(current_path): + # Do we have a current path + if current_path not in files_sizes.keys(): + files_sizes[current_path] = 0 + + # Add the files in this folder + for _, size in tree[containing_path]: + files_sizes[current_path] += size + + # print(f"Checking {check_path}... {current_path} is in it") + + # DEBUG: Print the files sizes + # for k, v in files_sizes.items(): + # print(f"Folder {k} contains {v} bytes of files") + return files_sizes + + +def part1(file_sizes): + + total = 0 + + # Now we can go through them all in this order + for _, total_size in file_sizes.items(): + if total_size <= 100_000: + total += total_size + + return total + + +def part2(file_sizes): + # How much free space do we have? + free_space = 70_000_000 - file_sizes["/"] + + # How much more do we need? + needed_space = 30_000_000 - free_space + + # Let's find the one folder which gets us to enough free space + space = 70_000_000 + for _, proposed in file_sizes.items(): + # Not enough space? + if proposed < needed_space: + continue + + # Found one, let's make sure it's the smallest + space = min(space, proposed) + + return space + + +if __name__ == "__main__": + + with open(root_path / "input", "r") as f: + # with open(root_path / "sample", "r") as f: + lines = [line.strip() for line in f.readlines()] + + tree = parse(lines) + file_sizes = get_file_sizes(tree) + + print(f"Part 1: Answer: {part1(file_sizes)}") + print(f"Part 2: Answer: {part2(file_sizes)}") diff --git a/skip-ahead-with-continue/code_disassembly.py b/skip-ahead-with-continue/code_disassembly.py new file mode 100644 index 0000000000..287b8f8f9b --- /dev/null +++ b/skip-ahead-with-continue/code_disassembly.py @@ -0,0 +1,15 @@ +import instaviz + + +def add_numbers(): + total = 0 + + for number in range(-10, 10): + if number < 0: + continue + total += number + + return total + + +instaviz.show(add_numbers) diff --git a/skip-ahead-with-continue/continue_finally.py b/skip-ahead-with-continue/continue_finally.py new file mode 100644 index 0000000000..afd2e97721 --- /dev/null +++ b/skip-ahead-with-continue/continue_finally.py @@ -0,0 +1,17 @@ +for number in range(2): + try: + print(f"Iteration {number}: start of try block") + + if number == 1: + print(f" Executing `continue` in iteration {number}...") + continue + + print(f" Normal flow in iteration {number}...") + + except Exception as e: + print(f"Iteration {number}: Exception: {e}") + + finally: + print(f"Iteration {number}: finally block") + + print(f"Iteration {number}: rest of loop body", end="\n\n") diff --git a/skip-ahead-with-continue/pyproject.toml b/skip-ahead-with-continue/pyproject.toml new file mode 100644 index 0000000000..ce84b81bba --- /dev/null +++ b/skip-ahead-with-continue/pyproject.toml @@ -0,0 +1,7 @@ +[project] +name = "skip-ahead-with-continue" +version = "0.1.0" +description = "Code for the Real Python tutorial on Python's `continue` keyword" +readme = "README.md" +requires-python = ">=3.8" +dependencies = ["instaviz"] diff --git a/skip-ahead-with-continue/sum_whole_numbers.py b/skip-ahead-with-continue/sum_whole_numbers.py new file mode 100644 index 0000000000..6cc52d4543 --- /dev/null +++ b/skip-ahead-with-continue/sum_whole_numbers.py @@ -0,0 +1,11 @@ +print("Enter one whole number per input.") +print("Type 0 to stop and display their sum:") + +total = 0 + +while (user_int := int(input("+ "))) != 0: + if user_int < 0: + continue + total += user_int + +print(f"{total=}")