Formatting and Understanding the Process for an "Unjumbler" - python

Basically, the code is supposed to print out what it believes to be the unjumbled letters based on the amount of one letter in an index. When I run it, it keeps saying stringlist is not defined. Any idea why? Could use some help with formatting too.
def getMessages():
stringlist=[]
stringinput=""
while stringinput!="DONE":
stringinput=input("Type each string. When you are finished, type DONE. ")
if stringinput=="DONE":
return stringlist
else:
stringlist.append(stringinput)
def countFrequencies(stringlist, indexval):
letterdict={"a":0, "b":0, "c":0, "d":0, "e":0, "f":0, "g":0, "h":0, "i":0, "j":0, "k":0, "l":0,
"m":0, "n":0, "o":0, "p":0, "q":0, "r":0, "s":0, "t":0, "u":0, "v":0, "w":0, "x":0,
"y":0, "z":0}
for i in stringlist:
counter=i[indexval]
letterdict[counter]+=1
return letterdict
def mostCommonLetter(letterdict):
ungarble=""
highest=-1
for i in letterdict.keys():
if letterdict[i]>highest:
ungarble=i
highest=letterdict[i]
return ungarble
getMessages()
countFrequencies(stringlist, indexval)
print("Recovered message: ", mostCommonLetter(letterdict))

Your indentation is incorrect.
You could use Counter to aggregate the frequencies of letters in each line.
from collections import Counter
def getMessages():
stringlist=[]
stringinput=""
while stringinput!="DONE":
stringinput=input("Type each string. When you are finished, type DONE. ")
if stringinput=="DONE":
return stringlist
else:
stringlist.append(stringinput)
def countFrequencies(stringlist):
frequencies = Counter()
for line in stringlist:
frequencies.update(line)
return frequencies
def mostCommonLetter(frequencies):
return max(frequencies)
stringlist = getMessages()
frequencies = countFrequencies(stringlist)
print("Recovered message: ", mostCommonLetter(frequencies))

Related

How do i add a "." between the letters of the initials?

Create a function called initials that takes in a persons names and then returns the initials. You should pass the names using **args.
For example for James Marshall Hendrix it should return J.M.H.
Or, for John Ronald Reuel Tolkien it should return J.R.R.T (one *arg to rule them all).
My outputs are JMH AND JRRT But i need to output them as the ones above.
def initials(*args):
result = ""
for word in args:
result += word[0].upper()
return result
if __name__ == "__main__":
print(initials("James", "Marshall", "Hendrix")) # should print the return value of "J.M.H"
print(initials("John", "Ronald", "Reuel", "Tolkien")) # should print the return value of "J.R.R.T"
def initials(*args):
result = []
for word in args:
result.append(word[0])
return ".".join(result)
if __name__ == "__main__":
print(initials("James", "Marshall", "Hendrix")) # should print the return value of "J.M.H"
print(initials("John", "Ronald", "Reuel", "Tolkien")) # should print the return value of "J.R.R.T"
Here is the fixed code, we store the result in a list instead of a string like how you did before, and we join the list with . at the end.
You can compact all that with a list comprehension:
def initials(*args):
return '.'.join([n[0] for n in args])
print(initials("James", "Marshall", "Hendrix"))
# J.M.H
print(initials("John", "Ronald", "Reuel", "Tolkien"))
# J.R.R.T
Edit: (thanks to azro): you can simplify it even further using a generator; it will be slower though (read ShadowRanger's very interesting comment below):
return '.'.join(n[0] for n in args)
Hi you can just add a "." when you take the first letter and then you can just return it without the first character anyway this method can
implement in any other programming language.
def initials(*args):
result = ""
for word in args:
result +="."+ word[0].upper()
return result[1:]
if __name__ == "__main__":
print(initials("James", "Marshall", "Hendrix"))
print(initials("John", "Ronald", "Reuel", "Tolkien"))

Python 3.7 : Variable switching between int and str depending on usage

I am working on a python Caesar cypher (for fun, I know it's not a good way to encrypt messages) and I ran into a problem. When I run the first bit of code, I get an error saying that the first arg in replace() must be a string, not an integer, when it is in face already a string ("TypeError: replace() argument 1 must be str, not int").
However, whenever I try to use it as an indice for a string, it tells me it is not an int ("TypeError: string indices must be integers").
Here is the code, thanks in advance. (There are a few more parts to the code but I don't think they're relevant to the question.)
def find_str(s, char):
index = 0
if char in s:
c = char[0]
for ch in s:
if ch == c:
if s[index:index+len(char)] == char:
return index
index += 1
return -1
class Alpha:
def __init__(self, message, key):
self.fKey = key
self.msg = str(message)
self.alpha = []
self.spcLoc = []
self.spcNum = 0
self.encryptedMessage = str(self.msg)
def encMsg(self):
for letter in self.spcNum):
str.replace(letter, find_str(self.alpha,letter) + self.fKey, self.spcNum)
def main():
msg = 'This is sparta'
key = 1
a = Alpha(msg, key)
a.encMsg()
for letter in self.spcNum:
This is a for-each loop which loops over every value in self.spcNum.
For example
for letter in ['a','b','c']:
print(letter)
will print out the letters a, b and c.
You can not iterate over self.spcNum. Because it is an integer (with the value 0) not a list.
There are other problems in the code too,
str.replace(letter, find_str(self.alpha,letter) + self.fKey, self.spcNum)
You're using this method incorrectly.
Correct usage:
stringYouWantEdited = "hi, my name is DGGB, hi"
substringYouWantReplaced = "hi"
newSubstring = "hello"
numberOfTimesThisShouldHappen = 1
newString = stringYouWantEdited.replace(substringYouWantReplaced , newSubstring , numberOfTimesThisShouldHappen )
print(newString)

Efficient partial search of a trie in python

This is a hackerrank exercise, and although the problem itself is solved, my solution is apparently not efficient enough, so on most test cases I'm getting timeouts. Here's the problem:
We're going to make our own Contacts application! The application must perform two types of operations:
add name, where name is a string denoting a contact name. This must store as a new contact in the application.
find partial, where partial is a string denoting a partial name to search the application for. It must count the number of contacts starting with partial and print the count on a new line.
Given n sequential add and find operations, perform each operation in order.
I'm using Tries to make it work, here's the code:
import re
def add_contact(dictionary, contact):
_end = '_end_'
current_dict = dictionary
for letter in contact:
current_dict = current_dict.setdefault(letter, {})
current_dict[_end] = _end
return(dictionary)
def find_contact(dictionary, contact):
p = re.compile('_end_')
current_dict = dictionary
for letter in contact:
if letter in current_dict:
current_dict = current_dict[letter]
else:
return(0)
count = int(len(p.findall(str(current_dict))) / 2)
re.purge()
return(count)
n = int(input().strip())
contacts = {}
for a0 in range(n):
op, contact = input().strip().split(' ')
if op == "add":
contacts = add_contact(contacts, contact)
if op == "find":
print(find_contact(contacts, contact))
Because the problem requires not returning whether partial is a match or not, but instead counting all of the entries that match it, I couldn't find any other way but cast the nested dictionaries to a string and then count all of the _end_s, which I'm using to denote stored strings. This, it would seem, is the culprit, but I cannot find any better way to do the searching. How do I make this work faster? Thanks in advance.
UPD:
I have added a results counter that actually parses the tree, but the code is still too slow for the online checker. Any thoughts?
def find_contact(dictionary, contact):
current_dict = dictionary
count = 0
for letter in contact:
if letter in current_dict:
current_dict = current_dict[letter]
else:
return(0)
else:
return(words_counter(count, current_dict))
def words_counter(count, node):
live_count = count
live_node = node
for value in live_node.values():
if value == '_end_':
live_count += 1
if type(value) == type(dict()):
live_count = words_counter(live_count, value)
return(live_count)
Ok, so, as it turns out, using nested dicts is not a good idea in general, because hackerrank will shove 100k strings into your program and then everything will slow to a crawl. So the problem wasn't in the parsing, it was in the storing before the parsing. Eventually I found this blogpost, their solution passes the challenge 100%. Here's the code in full:
class Node:
def __init__(self):
self.count = 1
self.children = {}
trie = Node()
def add(node, name):
for letter in name:
sub = node.children.get(letter)
if sub:
sub.count += 1
else:
sub = node.children[letter] = Node()
node = sub
def find(node, data):
for letter in data:
sub = node.children.get(letter)
if not sub:
return 0
node = sub
return node.count
if __name__ == '__main__':
n = int(input().strip())
for _ in range(n):
op, param = input().split()
if op == 'add':
add(trie, param)
else:
print(find(trie, param))

Using a dictionary to correct spelling

I need to write a function that takes a string argument and returns a string with the corrected spelling according to this dictionary:
For example:
"I ate teh whole thing lol"
comes out to be:
'I ate the whole thing haha'
I've done this so far but am lost on what to do:
def respell(string):
respellings = {
"teh":"the",
"relevent":"relevant",
"lite": "light",
"lol":"haha" }
respellingslist = reslepllings.split()
Try this :)
def respelling(string):
respellings = {
"teh": "the",
"relevent": "relevant",
"lite": "light",
"lol": "haha" }
res = string.split()
for i in xrange(len(res)):
if res[i] in respellings:
res[i] = respellings[res[i]]
return ' '.join(res)
[EDIT] one-liner:
return ' '.join(map(lambda s: respellings.get(s, s), string.split()))
Assuming that the respellings contains a lot of possible mistyped words as keys:
def respell(s):
respellings = {
"teh":"the",
"relevent":"relevant",
"lite": "light",
"lol":"haha" }
if s in respellings:
return respellings[s]
If it does not contain the required key it will do nothing.
The following function takes a string and corrects all the misspellings specified in the respellings dictionary passed as an argument:
def respell(s, respellings):
for wrong in respellings:
try:
index = s.index(wrong)
s = s[:index] + respellings[wrong] + s[len(wrong)+index:]
except:
print(wrong + " not in string")
return s
>>> print(respell("I aet teh wohle tingh",
{"aet":"ate", "teh":"the", "wohle":"whole", "tingh":"thing"}))
"I ate the whole thing"
If you want to only use a dictionary to correct spelling and all wrong spellings are present as key then your code should be as follows
def respell(word):
respellings = {
"teh":"the",
"relevent":"relevant",
"lite": "light",
"lol":"haha" }
try:
return respellings[word]
except KeyError:
return word
string = "I ate teh whole thing lol"
correct_string = " ".join(respell(word) for word in string.split())
and in-case if you want to do a proper spell check which would be slightly expensive is as follows.
from difflib import SequenceMatcher
def similar(a, b):
return SequenceMatcher(None, a, b).ratio()
def respell(word):
known_words = set(["the","man","relevant","light","haha"])
if word in known_words:
return word,1
max_similarity = 0
correct_word = None
for known_word in known_words:
similarity_value = similar(known_word, word)
if max_similarity<similarity_value:
similarity_value = max_similarity
correct_word = known_word
return correct_word,max_similarity
The above function returns two value a word and a similarity value which is between 0 and 1. zero (0) if no words are even near similar and 1 if given word is known or correct word.

Python string assignment issue!

So I'm fairly new to Python but I have absolutely no idea why this strong oldUser is changing to current user after I make the parse call. Any help would be greatly appreciated.
while a < 20:
f = urllib.urlopen("SITE")
a = a+1
for i, line in enumerate(f):
if i == 187:
print line
myparser.parse(line)
if fCheck == 1:
result = oldUser[0] is oldUser[1]
print oldUser[0]
print oldUser[1]
else:
result = user is oldUser
fCheck = 1
print result
user = myparser.get_descriptions(firstCheck)
firstCheck = 1
print user
if result:
print "SAME"
array[index+1] = array[index+1] +0
else:
oldUser = user
elif i > 200:
break
myparser.reset()
I don't understand why result doesn't work either... I print out both values and when they're the same it's telling me they're not equal... Also, why does myparser.parse(line) turn oldUser into a size 2 array? Thanks!
** Here's the definition for myparse...
class MyParser(sgmllib.SGMLParser):
"A simple parser class."
def parse(self, s):
"Parse the given string 's'."
self.feed(s)
self.close()
def __init__(self, verbose=0):
"Initialise an object, passing 'verbose' to the superclass."
sgmllib.SGMLParser.__init__(self, verbose)
self.divs = []
self.descriptions = []
self.inside_div_element = 0
def start_div(self, attributes):
"Process a hyperlink and its 'attributes'."
for name, value in attributes:
if name == "id":
self.divs.append(value)
self.inside_div_element = 1
def end_div(self):
"Record the end of a hyperlink."
self.inside_div_element = 0
def handle_data(self, data):
"Handle the textual 'data'."
if self.inside_div_element:
self.descriptions.append(data)
def get_div(self):
"Return the list of hyperlinks."
return self.divs
def get_descriptions(self, check):
"Return a list of descriptions."
if check == 1:
self.descriptions.pop(0)
return self.descriptions
Don’t compare strings with is. That checks if they’re the same object, not two copies of the same string. See:
>>> string = raw_input()
hello
>>> string is 'hello'
False
>>> string == 'hello'
True
Also, the definition of myparser would be useful.
I'm not quite sure what your code is doing, but I suspect you want to use == instead of is. Using is compares object identity, which is not the same as string equality. Two different string objects may contain the same sequence of characters.
result = oldUser[0] == oldUser[1]
If you're curious, for more information on the behaviour of the is operator see Python “is” operator behaves unexpectedly with integers.

Categories