I gave problem #22 on Project Euler a try in Python3.
Other than suggested in the instructions, I used
requests to fetch the file to work on.
The code below does produce the correct result but takes no measures to catch exceptions if something breaks, e.g. when the download is not successful.
I managed to split a string, in which names in double quotes are separated by a comma and turn it to a list, but I'm wondering if there isn't any better or more pythonic way.
As far as the summation of
int in a list is concerned, I'm aware that
functools might be an alternative, but for my first contribution here, I decided to keep it (more) simple.
#!/usr/bin/env python3 # -*- coding: utf-8 -*- '''Project Euler - Problem 22 - Name scores URL: https://projecteuler.net/problem=22 Resource (names.txt): https://projecteuler.net/project/resources/p022_names.txt Instructions: 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. Assignment: What is the total of all the name scores in the file? ''' import sys import requests URL = 'https://projecteuler.net/project/resources/p022_names.txt' def fetch_names(url): '''Get a text file with names and return a sorted list Parameters ---------- url : str url of a text file at Project Euler. Returns ------- alphabetically sorted list of first names ''' r = requests.get(url) # r.text is a string with names # the names are in capital letters, enclosed in double quotes # and separated by commas names = [name.strip('"') for name in r.text.split(',')] return sorted(names) def calculate_name_score(pos, name): ''' Calculate the "name sore" of a name at a specific position in a list Parameters ---------- pos : int zero-based index of a name in a list name : str name in CAPS Returns ------- name_score : int ''' # letter scores: 'A' = 1, 'B' = 2, etc.! ch_scores = [ord(ch) - 64 for ch in name] score = sum(ch_scores) # Project Euler: index of the names starts with 1!! name_score = score * (pos + 1) return name_score def calculate_total_score(names): '''Return a "name score" for a list of names Parameters ---------- names : list (of strings) Returns ------- total_score : int ''' scores = [calculate_name_score(pos, name) for (pos, name) in enumerate(names)] total_score = sum(scores) return total_score def main(): names = fetch_names(URL) result = calculate_total_score(names) print(result) if __name__ == '__main__': sys.exit(main())
I'm grateful for any improvement, regardless whether it concerns the structuring of code, naming, documentation, or anything you can think of.