Restructuring and optimization
The initial approach introduces inefficient file processing as get_content function reads all lines from the input file into a list at once and holds that list in memory throughout the entire processing. The traversal of the lines that were read is then redundantly repeated in run_code function.
The more efficient way is to convert get_content into a generator function and consume one line from file at a time on demand.
The optimized get_content function:
def get_content(file: str) -> List[str]:
"""
Yields lines from the passed file path
:param file -> str: File to read content
:return List[str]: Content in file
"""
with open(file, "r") as file:
for line in file:
yield line.rstrip()
run_code function is renamed to parse_code
Inefficiency of validating and traversing commands
In parse_code (formerly run_code) function the commands sequence is potentially being traversed twice:
once on correct_syntax(commands) call and then - on getting numbers chr(get_number(fish)) for fish in commands.
Moreover, consequent validations in this case may lead to redundant calculations.
Consider the following situation: commands contains 10 items, all of them passed correct_syntax check but then, the 9th item fails on get_number check. That causes 10 redundant operations/checks.
To optimize validations we notice that is_fish and get_number are conceptually dependent on the same context - "fish" and are intended to validate the same "fish" object.
Thus, those 2 validation are reasonably combined/consolidated into one validation function is_fish:
def is_fish(fish: str) -> bool:
"""
Validates "fish" item
Fish: Starts with >< ends with > and has number inside
A fish like so ><98g> will fail the check
"""
return fish.startswith("><") and fish.endswith(">") and fish[2:-1].isdigit()
get_number function is now removed.
The correct_syntax function is renamed to get_fish_numbers and its responsibility now is "Collect fish numbers from valid fishes":
def get_fish_numbers(pond: List[str]) -> bool:
"""
Collects fish numbers with checking the syntax of the passed list of commands on the following criteria:
Is a fish ><..>
Correct Example:
><98> ><108> ><56>
Incorrect Example:
><98> >><<76>> ><[108>
"""
fish_numbers = []
for fish in pond:
if not is_fish(fish):
sys.exit(f"Incorrect Syntax: {fish}")
fish_numbers.append(int(fish[2:-1]))
return fish_numbers
And finally the optimized parse_code function:
def parse_code(code: List[str]):
"""
Parse and output the passed Fishy Code
"""
for line in code:
# Clean up code and separate commands#
commands = line.split(" ")
# Check if line has multiple statements in it
fish_numbers = get_fish_numbers(commands)
if len(fish_numbers) > 1:
output = "".join(chr(num) for num in fish_numbers)
print(output)
else:
print(chr(fish_numbers[0]))