Project Euler 22, off by 18,609 - python

I'm working on problem 22 of Project Euler:
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?
My code (below) gets the answer 871179673. The correct answer should be 871198282, which makes me off by about 18k.
def score(name, pos):
score = 0
for letter in name:
if letter == "A": score += 1
elif letter == "B": score += 2
elif letter == "C": score += 3
elif letter == "D": score += 4
elif letter == "E": score += 5
elif letter == "F": score += 6
elif letter == "G": score += 7
elif letter == "H": score += 8
elif letter == "I": score += 9
elif letter == "J": score += 10
elif letter == "K": score += 11
elif letter == "L": score += 12
elif letter == "M": score += 13
elif letter == "N": score += 14
elif letter == "O": score += 15
elif letter == "P": score += 16
elif letter == "Q": score += 17
elif letter == "R": score += 18
elif letter == "S": score += 19
elif letter == "T": score += 20
elif letter == "U": score += 21
elif letter == "V": score += 22
elif letter == "W": score += 23
elif letter == "X": score += 24
elif letter == "Y": score += 25
elif letter == "Z": score += 26
else: score += 0
# end for loop.
return score * pos
#end def score.
f = open('names.txt')
string = f.readlines()
f.close()
names = sorted(str(string).split(","))
tscore = 0
pos = 1
for name in names:
tscore += score(name, pos)
pos += 1
#end for loop.
print tscore
If I run the 'Colin' example through my score function, I get the right result. I've tested a few other names from the list, and they score correctly as well. I googled the question and got various solutions, but since I'm new to python I'd like to learn what I did wrong. Thanks for your time!

Change this line:
names = sorted(str(string).split(","))
to:
names = sorted(string[0].split(','))
File contains just one line, so you need to access that line using string[0]. file.readlines returns a list containing all lines from the file, it's better to do something like:
names = f.read().split(',')
names.sort()
A shorter version of your program:
from string import ascii_uppercase
def score(word):
return sum(ascii_uppercase.index(c) + 1 for c in word.strip('"'))
with open('names.txt') as f:
names = f.read().split(',')
names.sort()
print sum(i*score(x) for i, x in enumerate(names, 1))
Note: string is a built-in module, don't use it as a variable name

import string
with open("names.txt",'r') as f:
d=f.read()
d=d.replace('"','')
#print(d)
names=d.split(',')
#print(names)
names.sort()
print(names)
gro=dict()
result=string.ascii_uppercase
count=1
for i in result:
gro[i]=count
count+=1
#print(gro)
sum=0
for ind,value in enumerate(names):
#print(ind,value)
temp=0
for x in value:
temp+=gro[x]
print(temp)
sum+=temp*(ind+1)
print(sum)

my way:
splitted = open('names.txt').read().replace('","',',').replace('"','').split(',')
description:
open the file, then read it, after that remove double qoutes by repalce them with none and at the end split the whole string by comma (,)
good luck

Related

How do I resolve: TypeError: unsupported operand type(s) for +: 'int' and 'list'

The issue occurs on line 70 - The function is def test().
if sum(characters) > [1]: TypeError: unsupported operand type(s) for +: 'int' and 'list'
For reference, this is a password strength checker.
How do I go about solving this? It seems like the code executes and can count the length of the input as well as add points to the score
import sys
import time
import random
import string # check for certain characters
def ten():
length = 10
chars = string.ascii_letters + string.digits + '!##$%^&*()'
rnd = random.SystemRandom()
print(''.join(rnd.choice(chars) for i in range(length)))
def fifteen():
length = 15
chars = string.ascii_letters + string.digits + '!##$%^&*()'
rnd = random.SystemRandom()
print(''.join(rnd.choice(chars) for i in range(length)))
def twenty():
length = 20
chars = string.ascii_letters + string.digits + '!##$%^&*()'
rnd = random.SystemRandom()
print(''.join(rnd.choice(chars) for i in range(length)))
def twentyfive():
length = 25
chars = string.ascii_letters + string.digits + '!##$%^&*()'
rnd = random.SystemRandom()
print(''.join(rnd.choice(chars) for i in range(length)))
def test():
# Password Checker
option = input()
upper_case = ([1 if c in string.ascii_uppercase else 0 for c in option])
lower_case = ([1 if c in string.ascii_lowercase else 0 for c in option])
special = ([1 if c in string.punctuation else 0 for c in option])
digits = ([1 if c in string.digits else 0 for c in option])
characters = [upper_case, lower_case, special, digits]
length = len(option)
score = 0
if length > 8:
score += 1
if length > 12:
score += 1
if length > 13:
score += 1
if length > 15:
score += 1
if length > 16:
score += 1
if length > 20:
score += 1
if length > 25:
score += 1
print(f"Password length is {str(length)}, adding {str(score)} points!")
if sum(characters) > 1:
score += 1
if sum(characters) > 2:
score += 1
if sum(characters) > 3:
score += 1
print(f"Password has {str(sum(characters))} different character types, adding {str(sum(characters) - 1)} points! ")
if score < 4:
print(f"Week {str(score)} / 7")
elif score == 4:
print(f"Week {str(score)} / 7")
elif 4 < score < 6:
print(f"Week {str(score)} / 7")
elif score > 6:
print(f"Week {str(score)} / 7")
def quit():
print("This program will now exit...")
time.sleep(2)
sys.exit()
# This is the menu function
def menu():
print("Hello Welcome To My Password Generator!!!")
time.sleep(1)
option = input("""
1: Generate a Random 10 Character Password
2: Generate a Random 15 Character Password
3: Generate a Random 20 Character Password
4: Generate a Random 25 Character Password
5: Test Password Strength
Q: Quit
Please decide on an option from 1, 2, 3, 4, 5 or Q:
""")
if option == "1":
ten()
elif option == "2":
fifteen()
elif option == "3":
twenty()
elif option == "4":
twentyfive()
elif option == "5":
test()
elif option == "Q" or option == "q":
quit()
else:
print("Error, you must enter a valid choice from the above menu")
menu()
menu()
I've redone your file to get rid of the unnecessary function calls, to eliminate the silly recursion, and to check the character classes in a better way. This does what you want, I believe.
import sys
import random
import string
alphabet = string.ascii_letters + string.digits + '!##$%^&*()'
def generate(length):
print(''.join(random.choice(alphabet) for i in range(length)))
def test():
# Password Checker
option = input()
upper_case = any(c in string.ascii_uppercase for c in option)
lower_case = any(c in string.ascii_lowercase for c in option)
special = any(c in string.punctuation for c in option)
digits = any(c in string.digits for c in option)
length = len(option)
score = 0
for k in [8,12,13,15,16,20,25]:
if length < k:
break
score += 1
print(f"Password length is {length}, adding {score} points!")
characters = sum([upper_case, lower_case, special, digits])
score += characters - 1
print(f"Password has {characters} different character types, adding {characters-1} points! ")
if score < 4:
print(f"Weak {score} / 7")
elif score < 5:
print(f"OK {score} / 7")
elif score < 6:
print(f"Medium {score} / 7")
else:
print(f"Strong {score} / 7")
# This is the menu function
def menu():
print("Hello Welcome To My Password Generator!!!")
while True:
option = input("""
1: Generate a Random 10 Character Password
2: Generate a Random 15 Character Password
3: Generate a Random 20 Character Password
4: Generate a Random 25 Character Password
5: Test Password Strength
Q: Quit
Please decide on an option from 1, 2, 3, 4, 5 or Q:
""")
if option == "1":
generate(10)
elif option == "2":
generate(15)
elif option == "3":
generate(20)
elif option == "4":
generate(25)
elif option == "5":
test()
elif option in "Qq":
break
else:
print("Error, you must enter a valid choice from the above menu")
menu()
characters = [upper_case, lower_case, special, digits]
creates a list of lists. sum(characters) won't work because that tries to add the lists to 0 to get the total, and you can't add a list to a number.
You should use
characters = upper_case + lower_case + special + digits
to concatenate all the lists instead of making nested lists.
In my case, with the original posted code, I was missing the any() function.
upper_case = any([1 if c in string.ascii_uppercase else 0 for c in option])
lower_case = any([1 if c in string.ascii_lowercase else 0 for c in option])
special = any([1 if c in string.punctuation else 0 for c in option])
digits = any([1 if c in string.digits else 0 for c in option])
Thank you for the help.

How do I call the values that I have defined in another function to the other function?

The problem that I have is that it says missing 3 required arguments when I try to pass it to the the other function, the arguments that I want to pass are guess_word, jug_words, and random_words so that I can use it for comparison
def InputData():
guess_word = input("Guess a word")
jug_words = GetJugWords()
random_words = GetRandomLetters()
def Score(jug_words, random_words, guess_word):
score = 0
while True:
print("Your phrase is: ", random_words)
guess_word = input("Guess a word: ")
score +=score
if len(guess_word) == 2 or len(guess_word) ==3 :
score += 1
elif len(guess_word) == 4:
score += 2
elif len(guess_word) == 5:
score += 3
elif len(guess_word) == 6 or len(guess_word) == 7:
score += 5
elif len(guess_word) == 8:
score += 8
if guess_word not in jug_words and random_words:
print("Game Over!")
break
print("Your score is now", str(score))
print(f"your total score: {score}")
I suggest you return the values from your InputData() function.
The current variables you are using do not exist outside the scope of the function.
You can return as a tuple, e.g.
def InputData():
...
return guess_word, jug_words, random_words
Then you can unpack the variables directly when you call the function:
guess_word, jug_words, random_words = InputData()
Score(jug_words, random_words, guess_word)

translating phone number with letter to all numbers in python. what am i doing wrong?

I keep getting only the first character displayed for the printed translated number
phoneNumLetter = str(input("Please enter a phone number that contains letters: "))
def translate(char):
if char.upper() == "A" or char.upper() == "B" or char.upper() == "C":
number = 2
elif char.upper() == "D" or char.upper() == "E" or char.upper() == "F":
number = 3
elif char.upper() == "G" or char.upper() == "H" or char.upper() == "I":
number = 4
elif char.upper() == "J" or char.upper() == "K" or char.upper() == "L":
number = 5
elif char.upper() == "M" or char.upper() == "N" or char.upper() == "O":
number = 6
elif char.upper() == "P" or char.upper() == "Q" or char.upper() == "R" or char.upper() == "S":
number = 7
elif char.upper() == "T" or char.upper() == "U" or char.upper() == "V":
number = 8
elif char.upper() == "W" or char.upper() == "X" or char.upper() == "Y" or char.upper() == "Z":
number = 9
return number
def translateNumber(phoneNumLetter):
for char in phoneNumLetter:
if char in['A','B','C','D','E','F','G','H','I','J','K','L','M','N','O','P','Q','R','S','T','U','V','W','X','Y','Z']:
result = translate(char)
return result
else:
return char
def main():
print("Your original phone number was: ", phoneNumLetter)
print("Your translated phone number is: ", translateNumber(phoneNumLetter))
main()
please help me figure out whats wrong. the point is to translate something like 1-800-FLOWERS to 1-800-3569377. for some reason if i input that the only return i get is "1"
In Python 2.7, an alternative solution that takes much less code is the following.
from string import maketrans
letter_to_num_table = maketrans("ABCDEFGHIJKLMNOPQRSTUVWXYZ", "22233344455566677778889999")
phoneNumLetter = str(input("Please enter a phone number that contains letters: "))
def main():
print("Your original phone number was: ", phoneNumLetter)
print("Your translated phone number is: ", phoneNumLetter.upper().translate(letter_to_num_table))
main()
The translate method of the string module was deprecated in Python 2.7, though, and removed in Python 3, so this doesn't work in Python 3.
While this seems to loop over all the characters,
def translateNumber(phoneNumLetter):
for char in phoneNumLetter:
if char in['A','B','C','D','E','F','G','H','I','J','K','L','M','N','O','P','Q','R','S','T','U','V','W','X','Y','Z']:
result = translate(char)
return result
else:
return char
In fact, it returns after processing the first character.
You probably want it to build a result string:
def translateNumber(phoneNumLetter):
result = ''
for char in phoneNumLetter:
if char in['A','B','C','D','E','F','G','H','I','J','K','L','M','N','O','P','Q','R','S','T','U','V','W','X','Y','Z']:
result = result + translate(char)
else:
result = result + char
return result
You're returning the character as soon as you translate it. You code prints the original phone number. Then, it calls translateNumber. translateNumber goes through the number until it finds an alphabet character. When it does, it translates it to a number and returns it. The 'return' acts as a break - the loop ends.
I'd recommend starting translate with char = char.upper(). Then you won't have to convert all of the characters to uppercase individually.
Here's a slightly cleaner version. This will add the letters as number and the numbers as numbers. It will ignore any characters that aren't numbers or letters. You could add a couple lines that would ensure properly sized phone numbers and insert correct phone number punctuation.
dict = {}
dict['A'] = 2
dict['B'] = 2
dict['C'] = 2
dict['D'] = 3
dict['E'] = 3
dict['F'] = 3
dict['G'] = 4
dict['H'] = 4
dict['I'] = 4
dict['J'] = 5
dict['K'] = 5
dict['L'] = 5
dict['M'] = 6
dict['N'] = 6
dict['O'] = 6
dict['P'] = 7
dict['Q'] = 7
dict['R'] = 7
dict['S'] = 7
dict['T'] = 8
dict['U'] = 8
dict['V'] = 8
dict['W'] = 9
dict['X'] = 9
dict['Y'] = 9
dict['Z'] = 9
def translateNumber(phoneNumLetter):
cleanNumber = ''
for char in phoneNumLetter:
if char.isalpha():
cleanNumber += str(dict[char.upper()])
if char.isdigit():
cleanNumber += str(char)
return cleanNumber
def main():
originalInput = str(input("Please enter a phone number: "))
print("Your original phone number was: " + originalInput)
print("Your translated phone number is: " + translateNumber(originalInput))
main()

Having trouble with an index Error

I am doing an assignment for my first computer programming course, and I am running into a problem. Basically this program is supposed to take a phonetically Hawaiian word, and produce a string that shows how to prounce it. However when I run the program, this happens:
stopProgram = 1
while stopProgram == 1:
validWord = 0
while validWord == 0:
#this while loop is has the user enter a word until it means Hawaiian syntax.
userWord = input("Please enter a valid hawaiian word.")
userWordEval = userWord.lower()
#changed the case for easier comparisons
validInput = 0
for j in range (len(userWordEval)):
#Test every character in the word to see if it meets the requirements. If it does, valid word is added 1.
if userWordEval[j] == "a" or userWordEval[j] == "e" or userWordEval[j] == "i" or userWordEval[j] == "o" or userWordEval[j] == "u" or userWordEval[j] == "p" or userWordEval[j] == "k" or userWordEval[j] == "h" or userWordEval[j] == "l" or userWordEval[j] == "m" or userWordEval[j] == "n" or userWordEval[j] == "w" or userWordEval[j] == "'" or userWordEval[j] == " ":
validInput += 1
if validInput == len(userWordEval):
#if the number in validWord is equal to the length of the word the user put in, that means that all the charaters were accepted. Otherwise, that means that something wasn't allowed, and will have to be reentered.
validWord = 1
else:
print("Invalid input. The accepted characters are: a, e, i, o, u, p, k, h, l, m, n, w, and '")
proWord = "" #Using this for the pronunciation string.
q = 0
while q <= len(userWordEval):
if userWordEval[q] == "a":
if len(userWordEval[q:]) > 1:
if userWordEval[q+1] == "i":
proWord += "-eye"
q += 2
elif userWordEval[q+1] == "e":
proWord += "-eye"
q += 2
elif userWordEval[q+1] == "o":
proWord += "-ow"
q += 2
elif userWordEval[q+1] == "u":
proWord += "-ow"
q += 2
elif userWordEval[q+1] == "'":
proWord += "-ah"
q += 2
else:
proWord += "-ah"
q += 1
else:
proWord += "-ah"
q += 1
elif userWordEval[q] == "e":
if len(userWordEval[q:]) > 1:
if userWordEval[q+1] == "i":
proWord += "-ay"
q += 2
elif userWordEval[q+1] == "u":
proWord += "-ow"
q += 2
elif userWordEval[q+1] == "'":
proWord += "-eh"
q += 2
else:
proWord += "-eh"
q += 1
else:
proWord += "-eh"
q += 1
elif userWordEval[q] == "i":
if len(userWordEval[q:]) > 1:
if userWordEval[q+1] == "u":
proWord += "-ay"
q += 2
elif userWordEval[q+1] == "'":
proWord += "-ee"
q += 2
else:
proWord += "-ee"
q += 1
else:
proWord += "-ee"
q += 1
elif userWordEval[q] == "o":
if len(userWordEval[q:]) > 1:
if userWordEval[q+1] == "i":
proWord += "-oy"
q += 2
elif userWordEval[q+1] == "u":
proWord += "-ow"
q += 2
elif userWordEval[q+1] == "'":
proWord += "-oh"
q += 2
else:
proWord += "-oh"
q += 1
else:
proWord += "-oh"
q += 1
elif userWordEval[q] == "u":
if len(userWordEval[q:]) > 1:
if userWordEval[q+1] == "i":
proWord += "-ooey"
q += 2
elif userWordEval[q+1] == "'":
proWord += "-oo"
q += 2
else:
proWord += "-oo"
q += 1
else:
proWord += "-oo"
q += 1
else:
q + 1
print(proWord)
stopProgram = 0
Output:
Please enter a valid hawaiian word.aeae Traceback (most recent call last):
File "C:/Users/Kristopher/Documents/Programming HW/Program
3.py", line 26, in <module>
if userWordEval[q] == "a": IndexError: string index out of range
string's index is from 0 to length-1. So change the while loop condition in line 24 to:
while q < len(userWordEval):
Your problem is that you are looping while q <= len(userWordEval). First of all, it is important to know that in python lists use zero-based indexing (see description on Wikipedia). This means that if there are 5 elements in a list, the last element will have index 4. The function len returns the number of elements in a list, so if you use that number as an index it will be too large. You can easily fix this by changing to q < len(userWordEval).
Remember list, string, tuple or other types which support indexing will raise IndexError if you try to access element past the index.
>>> a = 'apple'
>>> a[0]
'a'
>>> a[4]
'e'
>>> a[5]
Traceback (most recent call last):
File "<pyshell#5>", line 1, in <module>
a[5]
IndexError: string index out of range
So always use len(s)-1
>>> a[len(a)-1]
'e'
>>>
One nice bit of gotcha here. However during slicing you won't get that error. It will simple return an empty string/list.
>>> a[5:]
''
>>> a[:11]
'apple'

How to find certain letters in a string when there are multiple?

I want to be able to pick out certain letters in a string but need to be able to get the place of multiple rather then just the first (Python). I currently have this code:
word=apple #just and example
character=input("Take a guess")
if character == "a":
place=word.find("a")
elif character == "b":
place=word.find("b")
elif character == "c":
place=word.find("c")
elif character == "d":
place=word.find("d")
elif character == "e":
place=word.find("e")
elif character == "f":
place=word.find("f")
elif character == "g":
place=word.find("g")
elif character == "h":
place=word.find("h")
elif character == "i":
place=word.find("i")
elif character == "j":
place=word.find("j")
elif character == "k":
place=word.find("k")
elif character == "l":
place=word.find("l")
elif character == "m":
place=word.find("m")
elif character == "n":
place=word.find("n")
elif character == "o":
place=word.find("o")
elif character == "p":
place=word.find("p")
elif character == "q":
place=word.find("q")
elif character == "r":
place=word.find("r")
elif character == "s":
place=word.find("s")
elif character == "t":
place=word.find("t")
elif character == "u":
place=word.find("u")
elif character == "v":
place=word.find("v")
elif character == "x":
place=word.find("w")
elif character == "w":
place=word.find("x")
elif character == "y":
place=word.find("y")
else:
place=word.find("z")
This works to find the place of one letter, but if I wanted to find both p's it wouldn't work, it'd only tell me the position of the first. So what I'm really wondering is if there is some loop I can put it through to find the letters and set them as two different variables such as "place" and "place2" or do I have to have this same thing multiple different times for each separate starting point.
You can use re.finditer() to get all occurrences of the substring:
>>> import re
>>> word = "apple" #just and example
>>> character = input("Take a guess: ")
>>> for occurrence in re.finditer(character, word):
... print('character: {}, {}'.format(character, occurrence.start()))
Regular expressions are a powerful tool. However, there is a considerable overhead in using regexps for a trivial string literal search.
Here is a simple alternative repeatedly calling str.find until all occurrences are found:
def findall(mainstring, substring):
pos = -1
while True:
pos = mainstring.find(substring, pos+1)
if pos == -1:
break
yield pos
for occurence in findall("apple", "p"):
print(occurence)
# prints: 1 2

Categories