# -*- coding: utf-8 -*-
"""
Created on Wed Apr 13 17:07:03 2011
@author: pmav99
Project Euler - Problem 22
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?
"""
##------------------------------------------------------------------------------
from __future__ import division
import sys
import timeit
# needed for pyeuler
import string
# needed for lambdas2
if sys.version_info.major == 3:
from functools import reduce
# needed for regex
import re
def simple(fname = "names.txt"):
""" 2 consecutive loops. """
with open(fname, "r") as f:
names = sorted(f.read().replace('"', "").split(","))
tot = 0
for i, name in enumerate(names):
for char in name:
tot += (i + 1) * (ord(char) - 64)
return tot
def simple2(fname = "names.txt"):
""" 2 consecutive loops - a bit faster """
with open(fname, "r") as f:
names = sorted(f.read().replace('"', "").split(","))
tot = 0
for i, name in enumerate(names):
tot_name = 0
for char in name:
tot_name += (ord(char) - 64)
tot += (i + 1) * tot_name
return tot
def simple3(fname = "names.txt"):
""" One loop and a list comprehension. """
with open(fname, "r") as f:
names = sorted(f.read().replace('"', "").split(","))
tot = 0
for i, name in enumerate(names):
tot += (i + 1) * sum([ord(char) - 64 for char in name])
return tot
def list_generators(fname = "names.txt"):
""" One liner with list generator. Better memory usage, a little bit slower."""
with open(fname, "r") as f:
names = sorted(f.read().replace('"', "").split(","))
return sum((i+1) * sum(ord(c) - 64 for c in n) for i, n in enumerate(names))
def list_comprehension(fname = "names.txt"):
""" One liner with list comprehension. Worse memory usage, maybe a little bit faster."""
with open(fname, "r") as f:
names = sorted(f.read().replace('"', "").split(","))
return sum([(i+1) * sum(ord(c) - 64 for c in n) for i, n in enumerate(names)])
def lambdas(fname = "names.txt"):
""" from project euler solutions."""
with open(fname, "r") as f:
names = sorted(f.read().replace('"', "").split(","))
return sum(map(lambda x: (x[0]+1)*sum(map(lambda c: ord(c) - 64,x[1])),enumerate(names)))
def lambdas2(fname = "names.txt"):
""" from project euler solutions."""
with open(fname, "r") as f:
x = sorted(f.read().replace('"', "").split(","))
return reduce(lambda x, y: x + y, [reduce(lambda x, y: x + y, [(j + 1) * (ord(i) - 64) for i in x[j]]) for j in range(len(x))])
def lambdas3(fname = "names.txt"):
""" from project euler solutions."""
with open(fname, "r") as f:
names = sorted(f.read().replace('"', "").split(","))
return sum(sum(map(lambda x: ord(x) - 64, names[index])) * (index + 1) for index in range(len(names)))
def pyeuler(fname = "names.txt"):
""" from pyeuler at github solutions."""
with open(fname, "r") as f:
names = sorted(f.read().replace('"', "").split(","))
dictionary = dict((c, n) for (n, c) in enumerate(string.ascii_uppercase, 1))
return sum(i*sum(dictionary[c] for c in name) for (i, name) in enumerate(names, 1))
def pyeuler2(fname = "names.txt"):
""" from project euler solutions, with dictionary definition from pyeuler."""
with open(fname, "r") as f:
names = sorted(f.read().replace('"', "").split(","))
dictionary = dict((c, n) for (n, c) in enumerate(string.ascii_uppercase, 1))
return sum([sum([dictionary[x] for x in names[i]])*(i+1) for i in range(len(names))])
def regex(fname = "names.txt"):
"""
It is the same algorithm as simple2. The only difference is the usage
of the re module. It is slower, for this file size.
"""
tot = 0
for i, name in enumerate(sorted(re.compile("\"([A-Z]+)\"").findall(open(fname,"r").read()))):
name_total = 0
for c in name:
name_total += (ord(c) - 64)
tot += (i + 1) * name_total
return tot
def main():
repeat = 5
number = 1 # for time comparison
funcs = (simple, simple2, simple3, list_generators, list_comprehension,
lambdas, lambdas2, lambdas3, pyeuler, pyeuler2, regex)
print(50 * "-")
print("System information")
print(sys.version)
print(50 * "-")
print("Check solutions")
print(50 * "-")
for f in funcs:
print(f())
print(50 * "-")
print("Time comparison")
print(50 * "-")
for f in funcs:
t = timeit.Timer("{0}()".format(f.__name__),
"from __main__ import {0}".format(f.__name__))
print("{0:20} => {1}".format(f.__name__, min(t.repeat(repeat = repeat,
number = number))))
if __name__ == "__main__":
main()