I solved Project Euler 22 using Python 3. The problem reads as follows:
Using names.txt (right click and 'Save Link/Target As...'), a 46K text file containing over five-thousand first names, begin by sorting it into alphabetical order. Then working out the alphabetical value for each name, multiply this value by its alphabetical position in the list to obtain a name score.
For example, when the list is sorted into alphabetical order, COLIN, which is worth 3 + 15 + 12 + 9 + 14 = 53, is the 938th name in the list. So, COLIN would obtain a score of 938 × 53 = 49714.
What is the total of all the name scores in the file?
As you can see, the problem has much to do with handling lists of items and not so much with mathematics, unlike most other Euler problems. I chose to break the list of names, with the index/rank of each name as the key.
Are there ways to improve its performance that you can see? I'm also interested in any other possible improvements in style, naming, PEP8, etc.
'''
Project Euler 22: Names scores
https://projecteuler.net/problem=22
'''
import string
from typing import List, Dict
def get_names_from_file(file_path: str) -> List:
'''
Parses a text file containing names in this format:
"FOO","BAR","BAZ"
and returns a list of strings, e.g.,
["FOO","BAR","BAZ"]
'''
with open(file_path, "r") as file_:
return file_.read().replace("\"", "").split(",")
def get_sorted_indexed_dict(items: List, is_0_indexed: bool = False) -> Dict:
'''
Takes a list of strings and returns an alphabetically sorted dict
with the item's 1-indexed (by default) position as key, e.g.,
`list` arg: [ "FOO", "BAR", "BAZ" ]
returns: { 1 : "BAR", 2 : "BAZ", 3 : "FOO" }
The return dict can be 0-indexed by adding a 2nd argument as True.
'''
ix_start = 1
if is_0_indexed:
ix_start = 0
items = sorted(items)
numbered_dict = {}
for item in items:
numbered_dict[items.index(item) + ix_start] = item
return numbered_dict
def get_alpha_values() -> Dict:
'''
Assigns ASCII chars A-Z, inclusive, to a
number value 1-26, respectively.
'''
alpha_values = {}
index = 1
letters = list(string.ascii_uppercase)
for letter in letters:
alpha_values[letter] = index
index += 1
return alpha_values
def get_word_alpha_value(word: str, alpha_values: Dict) -> int:
'''
Calculates the value of each letter in the word
and returns the sum of the letter values.
'''
word_value = 0
for letter in list(word):
word_value += alpha_values[letter]
return word_value
def get_word_ranked_value(rank: int, word: str, alpha_values: Dict) -> int:
'''
Calculates the ranked value according to problem 22, i.e.,
the value of each word's letters multiplied by its
alphabetical rank.
'''
return rank * get_word_alpha_value(word, alpha_values)
def get_pe22_solution(file_path: str) -> int:
'''
Returns the solution to Project Euler 22 based on the file path provided.
'''
alpha_values = get_alpha_values()
# sanity check some alpha values
assert alpha_values['A'] == 1
assert alpha_values['Z'] == 26
assert alpha_values['S'] == 19
names = get_names_from_file(file_path)
names = get_sorted_indexed_dict(names)
# sanity checks name order based on PE 22 problem description
assert names[1] == "AARON"
assert names[938] == "COLIN"
assert names[5163] == "ZULMA"
name_values = [
get_word_ranked_value(k, v, alpha_values)
for (k, v) in names.items()
]
return sum(name_values)
if __name__ == "__main__":
FILE = "names.txt"
print("The answer to PE 22 is: {}".format(get_pe22_solution(FILE)))