Returning most used Letters while Looping - Python - python-3.x

How can I return the letter that is used the most in the for loop ?
My Code:
import string
def intefer_shift(encrypted_textfile, language):
index = 0
file_connector = open(encrypted_textfile,'r')
data = file_connector.read()
box =[]
data = data.lower()
file_connector.close()
times = 0
#this for loop is designed to count the number of times items appear in file
# this for loop is designed print each letter in the alphabet and tells how many times they appear
for letter in string.ascii_lowercase:
num = data.count(letter)
print(letter, ':', num)
intefer_shift('homework1.txt','English')

Simply add some kind of counter to store max_value, updated (if necessary) at every iteration of the loop.
top_letter = None
max_count = 0
for letter in string.ascii_lowercase:
num = data.count(letter)
print(letter, ':', num)
if num > max_count:
max_count = num
top_letter = letter
return top_letter
Mind the fact, that counting letters in probably big data-string one after another might be not efficient, and probably better option would be to loop all of the letters in data once and increment counter for each of them (this solution has worse space complexity, but better time complexity).

Related

Palindrome rearrangement in Python

I am given a string and I have to determine whether it can be rearranged into a palindrome.
For example: "aabb" is true.
We can rearrange "aabb" to make "abba", which is a palindrome.
I have come up with the code below but it fails in some cases. Where is the problem and how to fix this?
def palindromeRearranging(inputString):
a = sorted(inputString)[::2]
b = sorted(inputString)[1::2]
return b == a[:len(b)]
def palindromeRearranging(inputString):
return sum(map(lambda x: inputString.count(x) % 2, set(inputString))) <= 1
this code counts occurrence for every character in string. in palindromes there is one character with odd occurrence if length of string is odd, if length of string is even then no character has odd occurance.
see here
def palindromeRearranging(inputString):
elements = {c:inputString.count(c) for c in set(inputString)}
even = [e % 2 == 0 for e in elements.values()]
return all(even) or (len(inputString) % 2 == 1 and even.count(False) == 1)
It counts each character number of appearances, and checks whether all elements appear an even number of times or if the length of the input string is odd, checks whether only one character appears an odd number of times.
Python3
def palindromeArrange (string):
string = list(string)
for i in range (len(string)):
"""if the string has even element count"""
if len(string) % 2 == 0 and len(string)/2 == len (set (string)):
return True
"""if the string has odd element count"""
if len(string) - ((len(string)-1)/2) == len (set (string)):
return True
return False
One liner using list comprehension in Python3
return len([x for x in set(inputString) if inputString.count(x) % 2 != 0]) <= 1
Basically counts those characters that have counts that aren't divisible by 2.
For even strings it would be zero, and for odd strings, it would be one.
The solution I can think of right away has time complexity is O(n). The assumption is, palindrome can not be made if there is more than one character with the odd count.
def solution(inputString):
string = list(inputString)
n = len(string)
s_set= set(string)
from collections import Counter
dic = Counter(string)
k =0 #counter for odd characters
for char in s_set:
if dic.get(char)%2!=0:
k+=1
if k>1:
return False
else:
return True

Dealing with problems where memory isn't sufficient. Dynamic programming

I was solving a Problem using python, here i was storing a repetitive string "abc" in a string with everytime each character getting double like "abcaabbccaaaabbbbcccc.......... , and i had to find the nth character. The constraints were n<=10^9 , Now when i tried to store this their was memory error as the string was to too large (i tried to store all the charaters till the charater 2^30 times repeated). CAn somebody help me with the approach to tackle this situation.
t=' '
for i in range(0 , 30):
t = t +'a'*(2**i)
t = t +'b'*(2**i)
t = t +'c'*(2**i)
Obviously, you can't do this the straightforward, brute-force way. Instead, you need to count along a virtual string to find where your given index appears. I'll lay this out in too much detail so you can see the logic:
n = 314159265 # Pick a large value for illustration
rem = n
for i in range(0 , 30):
size = 2**i
# print(size, rem)
rem -= size
if rem <= 0:
char = 'a'
break
rem -= size
if rem <= 0:
char = 'b'
break
rem -= size
if rem <= 0:
char = 'c'
break
print("Character", n, "is", char)
Output:
Character 314159265 is b
You can shorten this with a better loop body; I'll leave that as a further exercise. If you get insightful with your arithmetic, you can simply compute the appropriate letter from the chunk sizes you generate.

Return number of alphabetical substrings within input string

I'm trying to generate code to return the number of substrings within an input that are in sequential alphabetical order.
i.e. Input: 'abccbaabccba'
Output: 2
alphabet = 'abcdefghijklmnopqrstuvwxyz'
def cake(x):
for i in range(len(x)):
for j in range (len(x)+1):
s = x[i:j+1]
l = 0
if s in alphabet:
l += 1
return l
print (cake('abccbaabccba'))
So far my code will only return 1. Based on tests I've done on it, it seems it just returns a 1 if there are letters in the input. Does anyone see where I'm going wrong?
You are getting the output 1 every time because your code resets the count to l = 0 on every pass through the loop.
If you fix this, you will get the answer 96, because you are including a lot of redundant checks on empty strings ('' in alphabet returns True).
If you fix that, you will get 17, because your test string contains substrings of length 1 and 2, as well as 3+, that are also substrings of the alphabet. So, your code needs to take into account the minimum substring length you would like to consider—which I assume is 3:
alphabet = 'abcdefghijklmnopqrstuvwxyz'
def cake(x, minLength=3):
l = 0
for i in range(len(x)):
for j in range(i+minLength, len(x)): # carefully specify both the start and end values of the loop that determines where your substring will end
s = x[i:j]
if s in alphabet:
print(repr(s))
l += 1
return l
print (cake('abccbaabccba'))

Replace isn't working for every letter in python

import time, random
#WELSCR
print(WOF1)
print("\n")
print(WOF2)
print("\n"*2)
input("Hit enter to play")
print("\n"*45)
print(WOF1)
print("\n")
print(WOF2)
doublespace = print("\n\n")
singlespace = print("\n")
tripplespace = print("\n\n\n")
guessed = []
score = 1000
wrong = 0
puzzle , hint = random.choice(questions)
blank = puzzle
for round in range (1,10):
tries = 0
iscorrect = False
while (not iscorrect) and (tries < 6):
blank = puzzle
for letter in blank:
if letter in "abcdefghijklmnopqrstuvwxyz":
blank = blank.replace(letter, "-")
def print_puzzle():
print("\n"*45)
print(WOF1)
print("\n")
print(WOF2)
print("\n"*2)
print(blank.center(80))
print("The hint is:",hint.title())
print("You currently have $",score)
print_puzzle()
input("enter")
break
break
This is the beginning of my program that I just started, a wheel of fortune game for a class. I can get it to replace almost all of the letters with a dash, however, there are the occasional few letters that do not always get hidden by this code and I'm not sure why. I have a variable defined as question which is a nested tuple but I did not include it because it's long and contains about 150 different entries.
Nevermind, the problem was case sensitivity. I had proper nouns and capitalized them, but I did not include capital letters in my replace string.

Using the random function in Python for Evil Hangman

What I am trying to do is alter my original hangman game into what is called evil hangman. In order to do this, I need to first generate a random length of a word and pull out all words of that length from the original list.
Here is the code I am working with:
def setUp():
"""shows instructions, reads file,and returns a list of words from the english dictionary"""
try:
print(60*'*' +'''\n\t\tWelcome to Hangman!\n\t
I have selected a word from an english dictionary. \n\t
I will first show you the length of the secret word\n\t
as a series of dashes.\n\t
Your task is to guess the secret word one letter at a time.\n\t
If you guess a correct letter I will show you the guessed\n\t
letter(s) in the correct position.\n
You can only make 8 wrong guesses before you are hanged\n
\t\tGood luck\n''' + 60*'*')
infile=open('dictionary.txt')
l=infile.readlines()# list of words from which to choose
infile.close()
cleanList = []
for word in l:
cleanList.append(l[:-1])
return(cleanList)
except IOError:
print('There was a problem loading the dictionary file as is.')
def sort_dict_words_by_length(words):
"""Given a list containing words of different length,
sort those words based on their length."""
d = defaultdict(list)
for word in words:
d[len(word)].append(word)
return d
def pick_random_length_from_dictionary(diction):
max_len, min_len = ( f(diction.keys()) for f in (max, min) )
length = random.randint(min_len, max_len)
return diction[length]
def playRound(w,g):
""" It allows user to guess one letter. If right,places letter in correct positions in current guess string g, and shows current guess to user
if not, increments w, number of wrongs. Returns current number of wrongs and current guess string"""
print('You have ' + str(8 - w) + ' possible wrong guesses left.\n')
newLetter = input('Please guess a letter of the secret word:\n')
glist = list(g)#need to make changes to current guess string so need a mutable version of it
if newLetter in secretWord:
for j in range (0,len(secretWord)):
if secretWord[j]==newLetter:
glist[j] = newLetter
g = ''.join(glist)#reassemble the guess as a string
print('Your letter is indeed present in the secret word: ' + ' '.join(g)+'\n')
else:
w += 1
print('Sorry, there are no ' + newLetter + ' in the secret word. Try again.\n')
return(w,g)
def endRound(wr, w,l):
"""determines whether user guessed secret word, in which case updates s[0], or failed after w=8 attempts, in s\which case it updates s[1]"""
if wr == 8:
l += 1
print('Sorry, you have lost this game.\n\nThe secret word was '+secretWord +'\n')#minor violation of encapsulation
else:
w +=1
print(15*'*' + 'You got it!' + 15*'*')
return(w,l)
def askIfMore():
"""ask user if s/he wants to play another round of the game"""
while True:
more = input('Would you like to play another round?(y/n)')
if more[0].upper() == 'Y' or more[0].upper()=='N':
return more[0].upper()
else:
continue
def printStats(w,l):
"""prints final statistics"""
wGames='games'
lGames = 'games'
if w == 1:
wGames = 'game'
if l ==1:
lGames = 'game'
print('''Thank you for playing with us!\nYou have won {} {} and lost {} {}.\nGoodbye.'''.format(w,wGames,l,lGames))
try:
import random
from collections import defaultdict
words=setUp()#list of words from which to choose
won, lost = 0,0 #accumulators for games won, and lost
while True:
wrongs=0 # accumulator for wrong guesses
secretWord = random.choice(words)[:#eliminates '\n' at the end of each line
print(secretWord) #for testing purposes
guess= len(secretWord)*'_'
print('Secret Word:' + ' '.join(guess))
while wrongs < 8 and guess != secretWord:
wrongs, guess = playRound(wrongs, guess)
won, lost = endRound(wrongs,won,lost)
if askIfMore()== 'N':
break
printStats(won, lost)
except:
quit()
What I would like to do is generate a random number with the lower bound being the shortest length word and the upper bound being the highest length word, and then use that random number to create a new container with words of only that length, and finally returning that container to be used by the game further. I tried using min and max, but it seems to only return the first and last item of the list instead of showing the word with the most characters. Any help is appreciated.
If your 'dictionary.txt' has a single word on each line, you could use the following, which is speed efficient, because it'll only go over the list once. But it'll consume the memory of your original list again.
from collections import defaultdict
import random
def sort_dict_words_by_length(words):
"""Given a list containing words of different length,
sort those words based on their length."""
d = defaultdict(list)
for word in words:
d[len(word)].append(word)
return d
def pick_random_length_from_dictionary(diction):
max_len, min_len = ( f(diction.keys()) for f in (max, min) )
length = random.randint(min_len, max_len)
return diction[length]
You would then pass the output from your setUp to sort_dict_words_by_length and that output to pick_random_length_from_dictionary.
If you are memory-limited, then you should first go over all words in the wordlist, keeping track of the minimal and maximal length of those words and then reiterate over that wordlist, appending only those words of the desired length. What you need for that is mentioned in the code above and just requires some code reshuffling. I'll leave that up to you as an exercise.

Resources