Python: Specific List Output Inconsistency - python

I believe the output I'm getting is a product of sloppy code somewhere, but I can't seem to get it. What I want my function to do is make a new list of the elements in a list it's being passed, in those elements' Pig-Latin translation. I've got the function working, but it makes all of the new list elements the Pig-Latin translation of only the first element in the list being passed to the function, even though I'm using an index to iterate through the elements of the passed list.
def pigLatin(targetlist):
newlist = ()
listnewlist = list(newlist)
index = 0 # gets incremented
firstletter = targetlist[index][0]
word = targetlist[index][1:]
print('Words made into Pig Latin: ')
while index < len(targetlist):
listnewlist.append(word + firstletter + 'ay')
index += 1
print(listnewlist)
which, after user input is "how now brown cow", displays:
['owhay', 'owhay', 'owhay', 'owhay']

word and firstletter are both computed outside of the loop and keep the value of first word of the targetlist.
IMHO, you should write :
def pigLatin(targetlist):
newlist = ()
listnewlist = list(newlist)
index = 0 # gets incremented
print('Words made into Pig Latin: ')
while index < len(targetlist):
firstletter = targetlist[index][0]
word = targetlist[index][1:]
listnewlist.append(word + firstletter + 'ay')
index += 1
print(listnewlist)

Related

How to count words that end with a letter? (python)

I am a beginner and this is what I came up with so far. However, it does not output the correct number of words that end with "a" or "b." Any tips on how to correct this code?
names = input("Enter list of names: ")
name = names.split(" ")
num = len(name)
ab = ""
print("Number of words:", num)
for i in range(num):
if name[i] == ' ':
if name[i-1] == a:
ab.append() + " "
elif name[i-1] == b:
ab.append() + " "
a_b = ab.split(' ')
print("Number of words that end with a or b: ",len(a_b))
In Python boolean (True and False) are the same as the integers 1 and 0. This means you can use sum() to count True booleans. str.endswith() returns a boolean. This means you can just do this:
words = ["stab", "drama", "hello", "magma", "test"]
a_b = sum(word.endswith(('a', 'b')) for word in words)
# 3
z_c = sum(word.endswith(('z', 'c')) for word in words)
# 0
Any tips on how to correct this code?
Others have answered alternative, working solutions, but I want to try to point out the specific things wrong in your code snippet and tips to correct.
First here's a copy of your snippet with some simple debugging prints along with their output (running in python 3.10).
names = "Barry Lima Bab"
name = names.split(" ")
print(f"{name=}") # name=['Barry', 'Lima', 'Bab']
num = len(name)
print(f"{num=}") # num=3
ab = ""
print("Number of words:", num)
for i in range(num):
print(name[i]) # Barry -> Lima -> Bab
if name[i] == ' ':
if name[i-1] == a:
ab.append() + " "
elif name[i-1] == b:
ab.append() + " "
print(f"{ab=}") # ab=''
a_b = ab.split(' ')
print(f"{a_b=}") # a_b=['']
Breaking things down step by step like this is a great starting point for better understanding what's going on.
if name[i] == ' ': Notice the value of name[i] so this check never resolves to True meaning the code inside never runs
if the inner code did run, you'd hit a NameError: name 'a' is not defined. Did you mean: 'ab'? because a is undefined. Probably meant 'a' here. same for b
In my example, name[i-1] would be 'Bab' -> 'Barry' -> 'Lima' which is probably not what you're expecting. This is because you're getting the -1th, 0th, 1st items in name. to get the last letter from the name, you want name[i][-1] here
if you then get into either of the furthest inside conditions, you'd encounter AttributeError: 'str' object has no attribute 'append' which happens because append is for list not str. You couldchange ab to be a list to use this in which case you'd want ab.append(name[i]) or you can use string concatenation like ab += " " + name[i] or using str.concat
1 last note of interest, you may have noticed your code as-is really likes to return and say that there's 1 item. This is because the above issues always (if the program doesn't break) leaves ab == '' and ''.split(' ') => [''] and thus len(ab.split(" ")) => 1
1 tip that I think would help in code comprehension is that the name variable here is not a single name string like it implies. It's actually a list[str]. I'd probably denote the variables something more like names_str: str vs names: list[str] or raw_names vs names. Then just use something like for name in names: and not worry about indexes. You can also use name.endswith('a') instead of name[-1] == 'a' for better readability.
Eventually you can combine these into a list comprehension for maximal succinctness -> len([name for name in names if name.endswith('a') or name.endswith('b')]).
words = ["ab", "bab", "pa", "pap"]
result = 0
for word in words:
if word[-1] in "ab":
result += 1
print(result)
As a list comprehension:
words = ["word1a", "word2b", "word3", "word4", "word5a"] # ['word1a', 'word2b', 'word5a']
filtered_words = [word for word in words if word[-1] in "ab"]
filtered_words = [word for word in words if word.endswith(("a", "b"))] # better, if you have multiple endings you want to search for with different lengths
len(filtered_words) # 3
name[i-1] is the previous name in the list, not the last character of the current name in the loop.
There's no need to append the matching names to a string. If you just need the count of matches, increment a counter variable.
You need to put a and b in quotes to make them strings, not variables.
names = input("Enter list of names: ")
name = names.split(" ")
matches = 0
print("Number of words:", len(name))
for cur_name in name:
if cur_name.endswith('a') or cur_name.endswith('b'):
matches += 1
print("Number of words that end with a or b: ", matches)
Use the endswith string method to detect if the last letter is "a" or "b"
names = ["bob","boba","larry","curly","moe"]
count = 0
for name in names:
if name.endswith("a") or name.endswith("b"):
count += 1
print(f"{count=}") # count=2

String index out of range in for each loop

My code glitches at the point its learning a letter in the code
while not cracked:
Word = "" # Word auto generates to learn a word
for element in range(0, len(WordLearning)):
print(element)
if(element in LettersItKnows):
Word = Word + WordLearning[element]
else:
if(Word[element] == WordLearning[element]): # Right Here it is weird
LettersItKnows.append(element)
else:
Word = Word + random.choice(Letters) ```
The problem here is that len() returns the number of elements in a list. but when you're getting an element from a list like this: myList[3] the first element is 0 which means that you need to do this:
while not cracked:
Word = "" # Word auto generates to learn a word
for element in range(len(WordLearning) - 1):
print(element)
if(element in LettersItKnows):
Word = Word + WordLearning[element]
else:
if(Word[element] == WordLearning[element]): # Right Here it is weird
LettersItKnows.append(element)
else:
Word = Word + random.choice(Letters) ```
You can see that all I did here was replace this: range(0, len(WordLearning)) by this: range(len(WordLearning) - 1) I got rid of the 0, because the range() starts on zero by default
Note that in this script if you reach this line: if(Word[element] == ... you'll get might get an error because there is a chance that the Word variable will still equal this: "" so you might fix that problem by setting Word to something that has more letters than the number of elements in the WordLearning variable. I can't really help you though because I don't understand anything about your script
This code will fail as soon as an character not in LettersItKnows is found, because the length of Word will then be equal to element, so Word[element], the element + 1th element of Word, will not exist.

python str object does not support item assignment

I'm trying to set the scrambled word from the list back to the list I have created, which is from split. I tried reading some of the solutions here and I think it's because you can't change the string in the list?
I'm not really sure correct me if I'm wrong :( . the sentence[i] = temp_word is giving the error. thanks in advance :)
class WordScramble:
def __init__(self):
self.user_input = input("Please give me a sentence: ")
def scramble(self):
# print what was input
print("The user input was: ", self.user_input)
# first scramble is just one word
print(self.user_input[0] + self.user_input[2] + self.user_input[1] + self.user_input[3:])
# reverse two indices
# particularly good to use is to switch the first two
# and the last two
# this only makes sense if you have a world that is longer than 3
# now try to scramble one sentence
sentence = self.user_input.strip().split(" ")
for i, word in enumerate(sentence):
if len(word) > 3:
temp_word = list(word)
if ',' in temp_word:
temp = temp_word[1]
temp_word[1] = temp_word[-3]
temp_word[-3] = temp
else:
temp = temp_word[1]
temp_word[1] = temp_word[2]
temp_word[2] = temp
temp_word = ''.join(temp_word)
sentence[i] = temp_word
sentence = ''.join(sentence)
print(sentence)
#print(" ".join(sentence))
# do just words first, then you can move on to work on
# punctuation
word_scrambler = WordScramble()
word_scrambler.scramble()
Because inside the for loop you wrote:
sentence = ''.join(sentence)
Thus, at the second iteration, the 'sentence' variable is now a string and in python, strings don't support item assignment as they are immutable variables. I think you meant to get this out of the for loop to print the final sentence.

how to reverse a sentence with a while loop

For an assignment, I need to use a while loop to reverse a list, and I just can't do it.
This is the sample code I have to help me get started:
sentence = raw_int (" ")
length = len(sentence) # determines the length of the sentence (how many characters there are)
index = length - 1 #subtracts one from the length because we will be using indexes which start at zero rather than 1 like len
while... #while the index is greater than or equal to zero continue the loop
letter = sentence[index] #take the number from the index in the sentence and assigns it to the variable letter
I need to use this in my solution.
sentence = raw_input(" ")
length = len(sentence)
index = length - 1
reversed_sentence = ''
while index >= 0:
#letter is the last letter of the original sentence
letter = sentence[index]
#make the first letter of the new sentence the last letter of the old sentence
reversed_sentence += letter
#update the index so it now points to the second to last letter of the original sentence
index = index - 1
print reversed_sentence
Because this is an assignment, I'm not going to give you the full code. But I will give you two 'hints'.
1) a sentenced is reversed if every character is 'flipped'. For example, 'I ran fast'-to flip this sentence first swap 'I' and 'f', then space and 's' and so on.
2) you can use syntax like:
Sentence[i], sentence[len(sentence)-i] = sentence[len(sentence)-i], Sentence[i]
This should definitely be enough to get you going.
You can do:
new_sentence = list()
sentence = list(raw_input(" "))
while sentence:
new_sentence.append(sentence.pop(-1))
else:
sentence = ''.join(new_sentence)

Reference next item in list: python

I'm making a variation of Codecademy's pyglatin.py to make a translator that accepts and translates multiple words. However, I'm having trouble translating more than one word. I've been able to transfer the raw input into a list and translate the first, but I do not know how to reference the next item in the list. Any help would be greatly appreciated.
def piglatin1():
pig = 'ay'
original = raw_input('Enter a phrase:').split(' ')
L = list(original)
print L
i = iter(L)
item = i.next()
for item in L:
if len(item) > 0 and item.isalpha():
word = item.lower()
first = word
if first == "a" or first == "e" or first == "i" or first == "o" or first =="u":
new_word = word + pig
print new_word
else:
new_word = word[1:] + word[0:1] + pig
# first word translated
L = []
M = L[:]
L.append(new_word)
print L # secondary list created.
again = raw_input('Translate again? Y/N')
print again
if len(again) > 0 and again.isalpha():
second_word = again.lower()
if second_word == "y":
return piglatin()
else:
print "Okay Dokey!"
else:
print 'Letters only please!'
return piglatin1()
I was working on this problem recently as well and came up with the following solution (rather than use range, use enumerate to get the index).
for index, item in enumerate(L):
next = index + 1
if next < len(L):
print index, item, next
This example shows how to access the current index, the current item, and then the next item in the list (if it exists in the bounds of the list).
Here are a few things to note that might help.
The lines i = iter(L) and item = i.next() are unnecessary. They have no effect in this method because you are redefining item immediately afterwards in the line for item in L. Go ahead and comment out those two lines to see if it makes any changes in your output.
The looping construct for item in L will go once over every item in the list. Whatever code you write within this loop will be executed once for each item in the list. The variable item is your handle to the list element of an iteration.
If, during any iteration, you really do want to access the "next" element in the list as well, then consider using a looping construct such as for i in range(0,len(L)). Then L[i] will be the current item and L[i+1] will you give the subsequent item.
There are some slight issues with the code but I think there is one main reason why it will not repeat.
In order to process the entire string the
again = raw_input('Translate again? Y/N')
and it's succeeding lines should be brought outside the for statement.
Also you appear to be setting L to an empty string inside the loop:
L = []
The following is a modified version of your code which will loop through the entire sentence and then ask for another one.
def piglatin():
pig = 'ay'
while True:
L = raw_input('Enter a phrase:').split(' ')
M = []
for item in L:
if len(item) > 0 and item.isalpha():
word = item.lower()
first = word
if first == "a" or first == "e" or first == "i" or first == "o" or first =="u":
new_word = word + pig
print new_word
else:
new_word = word[1:] + word[0:1] + pig
M.append(new_word)
else:
print 'Letters only please!'
print M # secondary list created.
again = raw_input('Translate again? Y/N')
print again
if len(again) > 0 and again.isalpha():
second_word = again.lower()
if second_word == "n":
print "Okay Dokey!"
break
Changes made:
You don't need to cast the return of the split to a list. The split
return type is a list.
It isn't necessary to make an iterator, the for loop will do this for you.
I removed the function as the return type. I'm assuming you were attempting some form of recursion but it isn't strictly necessary.
Hope this helps.
Step by step:
If you set variable original in this way:
original = raw_input('Enter a phrase:').split()
it will be already a list, so need to additional assignment.
What is the purpose of these lines?
i = iter(L)
item = i.next()
In a loop, you assign variable to the word, when it is actually only the first letter of the word, so it’ll be better like this: first = word[0]
Then if you want to check if first is a vowel, you can just do:
if first in 'aeuoiy'
Answer to your actual question: do not assign L to an empty list!
If you want to repeat the action of a function, you can just call it again, no need to rewrite the code.

Categories

Resources