So I'm trying to create a program that takes sentences and makes words of length 5 or longer reverse itself. At the moment it is only flipping the last word that meets the condition and I don't know why.
userInput = "Hello this is a test sentence"
wordList = userInput.split()
for i in wordList:
if len(i) >= 5:
reversedWord = i[::-1]
print(reversedWord)
reversedSentence = userInput.replace(i, reversedWord)
print(reversedSentence)
Instead of outputing "olleH this is a test ecnetnes" it outputs "Hello this is a test ecnetnes"
You keep replacing the original userInput
reversedSentence = userInput
for i in wordList:
if len(i) >= 5:
reversedWord = i[::-1]
print(reversedWord)
reversedSentence = reversedSentence.replace(i, reversedWord)
You need to keep updating the reversedSentence variable instead.
The actual bug in your code has already been stated, I just want to add some feedback regarding the style:
You are performing the following steps:
split the input into words
find words that meet your requirement (len(word) > 5)
change the original string for each of those
This is rather unconventional and a bit unintuitive (it also has bad performance, since it manipulates your original string multiple times). I recommend the following algorithm instead:
split the input into words
reverse the words meeting your requirement inside that list
join the list into a sentence again to get your string
Example implementation:
user_input = "Hello this is a test sentence"
processed_words = []
for word in user_input.split():
if len(word) >= 5:
word = word[::-1]
processed_words.append(word)
reversed_sentence = ' '.join(processed_words)
print(reversed_sentence)
Taking this idea a bit further by using a generator expression, it might look like this:
user_input = "Hello this is a test sentence"
reversed_sentence = ' '.join(
word[::-1] if len(word) >= 5 else word
for word in user_input.split())
print(reversed_sentence)
Related
I'm having trouble doing the next task:
So basically, I need to build a function that receives a (sentence, word, occurrence)
and it will search for that word and reverse it only where it occurs
for example:
function("Dani likes bananas, Dani also likes apples", "lik", "2")
returns: "Dani likes bananas, Dani also kiles apples"
As you can see, the "word" is 'lik' and at the second time it occurred it reversed to 'kil'.
I wrote something but it's too messy and that part still doesn't work for me,
def q2(sentence, word, occurrence):
count = 0
reSentence = ''
reWord = ''
for char in word:
if sentence.find(word) == -1:
print('could not find the word')
break
for letter in sentence:
if char == letter:
if word != reWord:
reWord += char
reSentence += letter
break
elif word == reWord:
if count == int(occurrence):
reWord = word[::-1]
reSentence += reWord
elif count > int(occurrence):
print("no such occurrence")
else:
count += 1
else:
reSentence += letter
print(reSentence)
sentence = 'Dani likes bananas, Dani also likes apples'
word = 'li'
occurrence = '2'
q2(sentence,word,occurrence)
the main problem right now is that, after it breaks it goes back to check from the start of the sentence so it will find i in "Dani". I couldn't think of a way to make it check from where it stopped.
I tried using enumerate but still had no idea how.
This will work for the given scenario
scentence = 'Dani likes bananas, Dani also likes apples'
word = 'lik'
st = word
occ = 2
lt = scentence.split(word)
op = ''
if (len(lt) > 1):
for i,x in enumerate(lt[:-1]):
if (i+1) == occ:
word = ''.join(reversed(word))
op = op + x + word
word = st
print(op+lt[-1])
Please test yourself for other scenario
This line for i,x in enumerate(lt[:-1]) basically loops on the list excluding the last element. using enumerate we can get index of the element in the list in i and value of element in x. So when code gets loops through it I re-join the split list with same word by which I broke, but I change the word on the specified position where you desired. The reason to exclude the last element while looping is because inside loop there is addition of word and after each list of element and if I include the whole list there will be extra word at the end. Hope it explains.
Your approach shows that you've clearly thought about the problem and are using the means you know well enough to solve it. However, your code has a few too many issue to simply fix, for example:
you only check for occurrence of the word once you're inside the loop;
you loop over the entire sentence for each letter in the word;
you only compare a character at a time, and make some mistakes in keeping track of how much you've matched so far.
you pass a string '2', which you intend to use as a number 2
All of that and other problems can be fixed, but you would do well to use what the language gives you. Your task breaks down into:
find the n-th occurrence of a substring in a string
replace it with another word where found and return the string
Note that you're not really looking for a 'word' per se, as your example shows you replacing only part of a word (i.e. 'lik') and a 'word' is commonly understood to mean a whole word between word boundaries.
def q2(sentence, word, occurrence):
# the first bit
position = 0
count = 0
while count < occurrence:
position = sentence.find(word, position+1)
count += 1
if position == -1:
print (f'Word "{word}" does not appear {occurrence} times in "{sentence}"')
return None
# and then using what was found for a result
return sentence[0:position] + word[::-1] + sentence[position+len(word):]
print(q2('Dani likes bananas, Dani also likes apples','lik',2))
print(q2('Dani likes bananas, Dani also likes apples','nope',2))
A bit of explanation on that return statement:
sentence[0:position] gets sentence from the start 0 to the character just before position, this is called a 'slice'
word[::-1] get word from start to end, but going in reverse -1. Leaving out the values in the slice implies 'from one end to the other'
sentence[position+len(word):] gets sentence from the position position + len(word), which is the character after the found word, until the end (no index, so taking everything).
All those combined is the result you need.
Note that the function returns None if it can't find the word the right number of times - that may not be what is needed in your case.
import re
from itertools import islice
s = "Dani likes bananas, Dani also likes apples"
t = "lik"
n = 2
x = re.finditer(t, s)
try:
i = next(islice(x, n - 1, n)).start()
except StopIteration:
i = -1
if i >= 0:
y = s[i: i + len(t)][::-1]
print(f"{s[:i]}{y}{s[i + len(t):]}")
else:
print(s)
Finds the 2nd starting index (if exists) using Regex. May require two passes in the worst case over string s, one to find the index, one to form the output. This can also be done in one pass using two pointers, but I'll leave that to you. From what I see, no one has offered a solution yet that does in one pass.
index = Find index of nth occurence
Use slice notation to get part you are interested in (you have it's beginning and length)
Reverse it
Construct your result string:
result = sentence[:index] + reversed part + sentence[index+len(word):]
Question:
Given an input string and a dictionary of words, find out if the input string can be segmented into a space-separated sequence of dictionary words. See following examples for more details.
Consider the following dictionary
{ i, like, sam, sung, samsung, mobile, ice,
cream, icecream, man, go, mango}
Input: ilike
Output: Yes
The string can be segmented as "i like".
Input: ilikesamsung
Output: Yes
The string can be segmented as "i like samsung" or
"i like sam sung".
I have tried the following recursive approach:
from timeit import timeit
def wordBreak(wordList, word):
word = word.replace(" ", "")
if word == '':
return True
else:
wordLen = len(word)
return any([(word[:i] in wordList)
and wordBreak(wordList, word[i:]) for i in range(1, wordLen+1)])
wordList = ["the", "quick", "fox", "brown"]
word = "the quick brown fox"
print(wordBreak(wordList,word))
print(timeit(lambda: wordBreak(wordList,word))) #12.690028140999999
I also tried using a Trie, which turned out to be way slower after benchmarking the run. Is there an iterative / OOP way of solving the same? Also is my current solution: O(n*(n-1)) in terms of time complexity?
I didn't see it at first, but there's a very similar way to do this without doing it one letter a time. At each recursion, check if you can remove an entire word at a time off the front of the string, and then just keep going. In an initial test or two, it appears to run a good bit faster.
I think this is the first time I've used the count argument to str.replace.
def word_break(word_list, text):
text = text.replace(' ', '')
if text == '':
return True
return any(
text.startswith(word)
and word_break(word_list, text.replace(word, '', 1))
for word in word_list
)
If you're using Python 3.9+, you can replace text.replace(word, '', 1) with text.removeprefix(word).
I believe it's the same asymptotic complexity, but with a smaller constant (unless the words in your allowed list are all single characters, anyway).
I think the best way to go about this is to use a for-loop in this way:
def wordBreak(wordList, word):
word = word.replace(" ", "")
if word == "":
return True
#No need for an else statement
llist = []
words = []
for i in range(len(word)):
llist.append(word[i])
for j in range(len(llist)):
if i != j:
llist[j] += word[i]
if llist[j] in wordList:
#print(llist[j])
words.append(llist[j])
return words
wordList = ["the", "quick", "fox", "brown"]
word = "the quick brown fox"
print(wordBreak(wordList,word))
Although it is a bit lengthier than your original one, it runs much quicker.
One part of my assignment is to get user input, convert that into a list, then depending on the number of characters in each word, change to upper/lower case accordingly. I have been told I have to use range, which is the part I am struggling with. This is my latest attempt but it's not working. Any advice would be appreciated.
poem = input("Enter a poem, verse or saying: ")
words_list = poem.split()
list_len = len(words_list)
for word in range(0,list_len):
if len(words_list[word]) < 4:
word = word.lower()
elif len(words_list[word]) > 6:
word = words.upper()
Just a small modification to your original code. Since you want to convert to upper/lower case, you also want to probably save the output. You can alternatively use a new list to save your output rather than replacing the values in the original list words_list
for word in range(0,list_len):
if len(words_list[word]) < 4:
words_list[word] = words_list[word].lower()
elif len(words_list[word]) > 6:
words_list[word] = words_list[word].upper()
print(words_list)
Output
Enter a poem, verse or saying: My name is bazingaa
['my', 'name', 'is', 'BAZINGAA']
How about this?
poem = input("Enter a poem, verse or saying: ")
words_list = poem.split()
out = ""
for word in words_list:
if len(word) < 4:
word = word.lower()
elif len(word) > 6:
word = word.upper()
out += " " + word
print(out)
Removed uneeded "list_len" variable, looped in "words_list" and checking length of "word". And concentrate output with "out" variable. For output there could be better techniques, I just did an easy one.
poem = input("Enter a poem, verse or saying: ")
words_list = poem.split()
list_len = len(words_list)
# word is not a word here, it was an integer
# by a convention we use 'i' for the iterator here
for i in range(0,list_len):
# here we assign an actual 'word' to the word variable
word = words_list[i]
if len(word) < 4:
# therefore you couldn't use .lower() or .upper() on the integer
word = word.lower()
elif len(word) > 6:
word = word.upper()
Use a proper IDE for coding like PyCharm. It would alert you about all the mistakes you've made.
That will work if you really need to use range, but you still need to figure out printing / returning the value.
If you don't know what's going on just put some prints wherever you need. You would figure it out by yourself if you put prints in your code.
Your code has a several problems. The word is the value of the iterator and so it is an integer. You can't use the functions upper and lower on integer. However, you can solve it in an easier way:
poem = input("Enter a poem, verse or saying: ")
words_list = poem.split()
for i in range(0,len(words_list)):
word = words_list[i]
word = word.lower() if len(word) < 4 else word
if len(word) > 6:word = word.upper()
print(word)
On executing the above code:
Enter a poem, verse or saying: Programming in Python is great
PROGRAMMING
in
Python
is
great
You can also make its function which returns a list (also uses range):
def get(string):
words_list = string.split()
output = []
for i in range(0,len(words_list)):
word = words_list[i]
word = word.lower() if len(word) < 4 else word
if len(word) > 6:word = word.upper()
output.append(word)
return output
print(get(input("Enter a poem, verse or saying: ")))
Testing:
Enter a poem, verse or saying: Programming in Python is great
['PROGRAMMING', 'in', 'Python', 'is', 'great']
I'm taking a class in python and now I'm struggling to complete one of the tasks.
The aim is to ask for an input, integrate through that string and print only words that start with letters > g. If the word starts with a letter larger than g, we print that word. Otherwise, we empty the word and iterate through the next word(s) in the string to do the same check.
This is the code I have, and the output. Would be grateful for some tips on how to solve the problem.
# [] create words after "G" following the Assignment requirements use of functions, menhods and kwyowrds
# sample quote "Wheresoever you go, go with all your heart" ~ Confucius (551 BC - 479 BC)
# [] copy and paste in edX assignment page
quote = input("Enter a sentence: ")
word = ""
# iterate through each character in quote
for char in quote:
# test if character is alpha
if char.isalpha():
word += char
else:
if word[0].lower() >= "h":
print(word.upper())
else:
word=""
Enter a sentence: Wheresoever you go, go with all your heart
WHERESOEVER
WHERESOEVERYOU
WHERESOEVERYOUGO
WHERESOEVERYOUGO
WHERESOEVERYOUGOGO
WHERESOEVERYOUGOGOWITH
WHERESOEVERYOUGOGOWITHALL
WHERESOEVERYOUGOGOWITHALLYOUR
The output should look like,
Sample output:
WHERESOEVER
YOU
WITH
YOUR
HEART
Simply a list comprehension with split will do:
s = "Wheresoever you go, go with all your heart"
print(' '.join([word for word in s.split() if word[0].lower() > 'g']))
# Wheresoever you with your heart
Modifying to match with the desired output (Making all uppercase and on new lines):
s = "Wheresoever you go, go with all your heart"
print('\n'.join([word.upper() for word in s.split() if word[0].lower() > 'g']))
'''
WHERESOEVER
YOU
WITH
YOUR
HEART
'''
Without list comprehension:
s = "Wheresoever you go, go with all your heart"
for word in s.split(): # Split the sentence into words and iterate through each.
if word[0].lower() > 'g': # Check if the first character (lowercased) > g.
print(word.upper()) # If so, print the word all capitalised.
Here is a readable and commented solution. The idea is first to split the sentence into a list of words using re.findall (regex package) and iterate through this list, instead of iterating on each character as you did. It is then quite easy to print only the words starting by a letter greater then 'g':
import re
# Prompt for an input sentence
quote = input("Enter a sentence: ")
# Split the sentence into a list of words
words = re.findall(r'\w+', quote)
# Iterate through each word
for word in words:
# Print the word if its 1st letter is greater than 'g'
if word[0].lower() > 'g':
print(word.upper())
To go further, here is also the one-line style solution based on exactly the same logic, using list comprehension:
import re
# Prompt for an input sentence
quote = input("Enter a sentence: ")
# Print each word starting by a letter greater than 'g', in upper case
print(*[word.upper() for word in re.findall(r'\w+', quote) if word[0].lower() > 'g'], sep='\n')
s = "Wheresoever you go, go with all your heart"
out = s.translate(str.maketrans(string.punctuation, " "*len(string.punctuation)))
desired_result = [word.upper() for word in out.split() if word and word[0].lower() > 'g']
print(*desired_result, sep="\n")
Your problem is that you're only resetting word to an empty string in the else clause. You need to reset it to an empty string immediately after the print(word.upper()) statement as well for the code as you've wrote it to work correctly.
That being said, if it's not explicitly disallowed for the class you're taking, you should look into string methods, specifically string.split()
I would like to compare the input letters(dictionary) with the list(textfile with words) and print the words matching the inputed letters. What have I done wrong?(I know i only have a print YES or NO-function if it finds a matching word at the moment. What's the best way to create this function by the way?).
def ordlista(list):
fil = open("ord.txt", "r")
words = fil.readlines()
list = []
for w in words:
w = w.strip()
list.append(w)
return list
chars = {}
word = raw_input("Write 9 letters: ")
for w in word:
w = w.lower()
if w not in chars:
chars[w] = 1
else:
chars[w] += 1
if chars.keys() in ordlista(list):
print "YES"
else:
print "NO"
chars.keys() is a list, so
chars.keys() in ordlista(list):
will never be True. What you want is match the letter counts against each word in your list. So I'd suggest
charsum = sum(chars.values())
for word in wordlist:
if len(word) == charsum and all([(word.count(c) == chars[c]) for c in chars]):
print "YES for word '%s'" % word
EDIT: If you want those words to match which have at least the letter counts (i.e. a word with 3 a's will match an input of two a's), then you'll have to change the == to a >=.
EDIT2: Since you want exact matches, the easiest solution would be to count the number of chars and make sure the word has that length.
You are checking for the presence of the entire list of keys in your character list, rather than checking for each key individually. You must iterate over your keys individually, and then check for their presence.
for k in chars:
if k in ordlista(list):
print "YES"
else:
print "NO"
If you want to print the words which consist solely of the letters in your character list, you may use the following approach.
for word in ordlista(list):
if not filter(lambda char: char not in chars, word):
print word
Use sets:
chars = set(raw_input("Write 9 letters: "))
for word in ordlista(None):
if(set(word) == chars):
print "YES for '%s'" % word
BTW, the argument list to ordlista is unnecessary, as it is not used. I would also advise against using the name list in general, because it hides the built-in <type 'list'>
Update: I have read your comment on jellybean's post. If every letter can only be used once, you can obviously not use sets!