Closed. This question needs debugging details. It is not currently accepting answers.
Edit the question to include desired behavior, a specific problem or error, and the shortest code necessary to reproduce the problem. This will help others answer the question.
Closed 5 years ago.
Improve this question
Im a beginner to your world. I have seen many attempts to answer this question using fancy builtin function and have found the answer on how to do this a thousand times but NONE using two for loops method.
I would like for the code to only reverse a vowel when it finds one in a string, using the two for loop method.
I coded something that didnt seem to work and I dont quite understand why,
for x in newWord:
for y in vowels:
if x == y:
newWord[x] = newWord[7]
print newWord
with vowels being a list of vowels, with newWord also being a list.
This code is currently not working, like most others who have tried the two for loop method. Any help is appreciated. Thanks
Roughly the approach you want to use is to make two passes over the list of characters. In the first pass you find the index of each vowel, building a list of work to be done (locations of vowels to be swapped).
Then you prepare your work list by matching the first and last items until you have less than two items left in the work list. (An odd number of vowels means that the one in the middle doesn't have to be swapped with anything).
Now you simply iterate over the work list, tuples/pairs of indexes. Swap the character at the first offset with the character at the other one for each pair. Done.
(This is assuming you want transform the list in place. If not then you can either just start with a copy: new_word = word[:] or can iterate over enumerate(word) and conditionally either append the character at each point (if the offset isn't in your work list) ... or append the offset character (if this index matches one of those in your list). I the latter case you might make your work list a dictionary instead).
Here's the code to demonstrate:
def rev_vowels(word):
word = list(word)
results = word[:]
vowel_locations = [index for index, char in enumerate(word) if char in 'aeiou']
work = zip(vowel_locations[:int(len(vowel_locations)/2)], reversed(vowel_locations))
for left, right in work:
results[left], results[right] = word[right], word[left]
return results
This does use a list comprehension, the zip() and reversed() builtins, a complex slice for the first argument to zip(), and the Python tuple packing idiom for swapping variables. So you might have to replace those with more verbose constructs to fulfill your "no fancy builtins" constraint.
Fundamentally, however, a list comprehension is just syntactic sugar around a for loop. So, overall, this demonstrates the approach using two for loops over the data. While I'm returning a copy of the data as my results the code would work without that. (That's why I'm using the tuple packing idiom on line seven (just before the return statement).
If this question is being asked in an interview context I'm reasonably confident that this would be a reasonably good answer. You can easily break down how to implement zip, how to expand a list comprehension into a traditional for suite (block), and the swap line could be two separate assignments when returning a copy rather than performing an in-place transformation on the data.
These variable names are very verbose. But that's to make the intentions especially clear.
This code should solve your problem without using any "fancy builtin functions".
def f(word):
vowels = "aeiou"
string = list(word)
i = 0
j = len(word)-1
while i < j:
if string[i].lower() not in vowels:
i += 1
elif string[j].lower() not in vowels:
j -= 1
else:
string[i], string[j] = string[j], string[i]
i += 1
j -= 1
return "".join(string)
Related
I have the following program which seeks to check the similarity between two lists. However, the originalword (list) prints correctly the first time but not the second therefore the code doesn't work to check equivalence.
https://trinket.io/python3/b3b7827717
Can anyone spot the error? If so, could a solution be posted
a) using lists
b) Not introducing any new skills (e.g. string slicing)
def palindromechecker():
print("----Palindrome Checker---")
word=input("Enter word:")
#empty list for reversed word
originalword=[]
reversedword=[]
#put each letter in word in the list originallist
for i in range(len(word)):
originalword.append(word[i])
print("Print original word in order:",originalword)
#reverse the word
for i in range(len(word)):
reversedword.append(originalword.pop())
print("Reversed word:",reversedword)
print("Original word:",originalword)
#are original word and reversed word the same?
if originalword==reversedword:
print("--Palindrome Found--")
else:
print("--Not a Palindrome---")
palindromechecker()
You make originalword list empty by doing that originalword.pop() in the second loop. Better way to do that is just reverse list like that
reversedword = originalword[::-1]
It will work without loop
Or you can do something like that:
for i in range(len(word)):
reversedword.append(originalword[-1-i])
If you use .pop() method, it will update the existing list by removing the last element from the list. So it is exhausting your originalword list.
I read that you don't want to use string[::-1]. Here is a similar but not the same workaround. You have to run the loop in reverse.
#reverse the word
for i in range(len(word)-1, -1, -1):
reversedword.append(originalword[i])
I am confused about when using a while-loop or for-loop is better? I am particularly worried about producing optimized answers to coding questions. I find myself solving problems just to find out a while-loop would've been faster but am confused about what leads people to choose to use it instead of a for-loop, like what criteria should I be looking for?
Here's an example of a coding question I answered which checks if a string of parentheses is balanced.
def parenCheck(str):
stack = Stack()
for x in str:
if x == '(':
stack.push(x)
else:
if stack.isEmpty():
return False
else:
stack.pop()
return stack.isEmpty()
Here is the answer I saw for it , which I know is faster because it doesnt use a for-loop:
def parChecker(symbolString):
s = Stack()
balanced = True
index = 0
while index < len(symbolString) and balanced:
symbol = symbolString[index]
if symbol == "(":
s.push(symbol)
else:
if s.isEmpty():
balanced = False
else:
s.pop()
index = index + 1
if balanced and s.isEmpty():
return True
else:
return False
For the same number of iterations, and content, my guess is that a for loop and wihile have practically the same speed. But I haven't tested that - mostly I answer numpy questions where we try to avoid either loop (preferring iterations in compiled code).
Your examples show the basic case where for results in cleaner, if not faster, code:
for x in an_iterator:
<do something>
versus
i = 0
while i < len(an_iterator):
x = an_iterator[x]
<do something>
i += 1
If you must have an index as well, you can use:
for i, x in enumerate(an_iterator):
....
That ability to iterate directly on things like lists and dictionaries was the main neat feature that caught my attention when I first saw Python in the 1990.
A common subcase of a for loop accumulates values, so common, that Python provides the popular list comprehension, and extended the syntax to generator expressions and dictionary comprehensions.
while still has its uses. Other languages have do while and do until variants, which attempt to streamline stepping the variable and testing. Python has just the one version with separate steps. The new walrus operator has the potential of cleaning that up:
https://docs.python.org/3/whatsnew/3.8.html#assignment-expressions
while (block := f.read(256)) != '':
process(block)
while is most useful when the steps aren't regular, or from a well defined iterator. for can break and continue, but otherwise the sequence is fixed (at the start of iteration).
In addition to enumerate, zip lets us iterate on several things at once.
The convenience of list comprehensions encourages us to decompose a complicated task into a sequence of comprehensions. And to make that even more convenient (and faster/memory efficient) Python provides generators and all sort so itertools. In Python 3, range and dictionary keys/items/values all became generator like expressions.
This cannot be decided by your code that while loop worked faster than for loop. As of your question on when to use while and for loop, it is decided on the basis of whether we know the number of iterations. If number of iterations is known, for loop is preferred, whereas while loop is preferred when the iterations are indefinite.
for (int i : mynumber_list)
Iterator it = mynumber_list.iterator()
while (it.hasNext())
As can be seen from above, for loop is more readable, simple, and easy in traversing. Moreover, iterator.hasNext() has a very high probability of entering into an infinite loop
while can also be useful for user choice input questions, like keep executing the program until the user presses any other key except y. This is difficult to achieve with for loop.
I have discovered something in python today. But haven't found a clear explanation for it yet.
In python it seems that this works:
variable += a_single_statement
So, following statements are correct:
variable += another_variable
variable += (another_variable - something_else)
But doing the following is incorrect:
variable += a_variable - b_variable
Could someone explain why this is the case, preferably with a link to the documentation to the syntactical structure that explains what the operands of a += operator are, what expressions are expected and what their structure is? Also, are my thoughts, outlined above, even correct?
The behavior seems to be different from other programming languages I'm used too, and that last 'statement' leads to a syntax error.
Edit: the code where it doesn't work. It might be a whitespace error instead :/
T = input()
counter = 0
# For each word, figure out edit length to palindrome
for _ in range(T):
counter += 1
word = raw_input()
word_len = len(word) #stored for efficiency
index = 0
sum_edits = 0
# Iterate half the word and always compare characters
# at equal distance d from the beginning and from
# the ending of the word
while index < word_len/2.0:
sum_edits += max(ord(word[index]), ord(word[word_len-index-1])) -
min(ord(word[index]), ord(word[word_len - index - 1]))
index += 1
print sum_edits
It's code to detect how many edits it would take to make a word into a palindrome, if you could only change letters 'downwards' towards an 'a'.
Does this mean you can not arbitrarily break up a line in python code, if it's clear that the 'expression' has to continue anyway? Or can you only break up lines of code if they are surrounded with parentheses?
Sorry, I'm very new to python.
It has nothing to do with +=. It's just that Python doesn't let you split a statement across multiple lines unless there's an open (, {, or [, or unless you perform a line continuation with \. It might look obvious that those two lines are supposed to be one statement, but then when you have statements like
a = loooooooooooooooooooooooooooooong_thiiiiiiiiiiiiiiiiiiiiiiiing
+ ooooooooooooootheeeeeeeeeeeeer_thiiiiiiiiiiiiiiiiiiiing
is that one statement or two? If you allow
a = loooooooooooooooooooooooooooooong_thiiiiiiiiiiiiiiiiiiiiiiiing +
ooooooooooooootheeeeeeeeeeeeer_thiiiiiiiiiiiiiiiiiiiing
to be one statement, then either interpretation for having the + operator on the second line is confusing and bug-prone. Javascript tries to allow this kind of thing, and its semicolon insertion causes all kinds of problems.
It's usually recommended to use parentheses if you're not already inside brackets or braces.
I am just learning programming in Python for fun. I was writing a palindrome program and I thought of how I can make further improvements to it.
First thing that came to my mind is to prevent the program from having to go through the entire word both ways since we are just checking for a palindrome. Then I realized that the loop can be broken as soon as the first and the last character doesn't match.
I then implemented them in a class so I can just call a word and get back true or false.
This is how the program stands as of now:
class my_str(str):
def is_palindrome(self):
a_string = self.lower()
length = len(self)
for i in range(length/2):
if a_string[i] != a_string[-(i+1)]:
return False
return True
this = my_str(raw_input("Enter a string: "))
print this.is_palindrome()
Are there any other improvements that I can make to make it more efficient?
I think the best way to improvise write a palindrome checking function in Python is as follows:
def is_palindrome(s):
return s == s[::-1]
(Add the lower() call as required.)
What about something way simpler? Why are you creating a class instead of a simple method?
>>> is_palindrome = lambda x: x.lower() == x.lower()[::-1]
>>> is_palindrome("ciao")
False
>>> is_palindrome("otto")
True
While other answers have been given talking about how best to approach the palindrome problem in Python, Let's look at what you are doing.
You are looping through the string by using indices. While this works, it's not very Pythonic. Python for loops are designed to loop over the objects you want, not simply over numbers, as in other languages. This allows you to cut out a layer of indirection and make your code clearer and simpler.
So how can we do this in your case? Well, what you want to do is loop over the characters in one direction, and in the other direction - at the same time. We can do this nicely using the zip() and reversed() builtins. reversed() allows us to get the characters in the reversed direction, while zip() allows us to iterate over two iterators at once.
>>> a_string = "something"
>>> for first, second in zip(a_string, reversed(a_string)):
... print(first, second)
...
s g
o n
m i
e h
t t
h e
i m
n o
g s
This is the better way to loop over the characters in both directions at once. Naturally this isn't the most effective way of solving this problem, but it's a good example of how you should approach things differently in Python.
Building on Lattyware's answer - by using the Python builtins appropriately, you can avoid doing things like a_string[-(i+1)], which takes a second to understand - and, when writing more complex things than palindromes, is prone to off-by-one errors.
The trick is to tell Python what you mean to do, rather than how to achieve it - so, the most obvious way, per another answer, is to do one of the following:
s == s[::-1]
list(s) == list(reversed(s))
s == ''.join(reversed(s))
Or various other similar things. All of them say: "is the string equal to the string backwards?".
If for some reason you really do need the optimisation that you know you've got a palindrome once you're halfway (you usually shouldn't, but maybe you're dealing with extremely long strings), you can still do better than index arithmetic. You can start with:
halfway = len(s) // 2
(where // forces the result to an integer, even in Py3 or if you've done from __future__ import division). This leads to:
s[:halfway] == ''.join(reversed(s[halfway:]))
This will work for all even-length s, but fail for odd length s because the RHS will be one element longer. But, you don't care about the last character in it, since it is the middle character of the string - which doesn't affect its palindromeness. If you zip the two together, it will stop after the end of the short one - and you can compare a character at a time like in your original loop:
for f,b in zip(s[:half], reversed(s[half:])):
if f != b:
return False
return True
And you don't even need ''.join or list or such. But you can still do better - this kind of loop is so idiomatic that Python has a builtin function called all just to do it for you:
all(f == b for f,b in zip(s[:half], reversed(s[half:])))
Says 'all the characters in the front half of the list are the same as the ones in the back half of the list written backwards'.
One improvement I can see would be to use xrange instead of range.
It probably isn't a faster implementation but you could use a recursive test. Since you're learning, this construction is very useful in many situation :
def is_palindrome(word):
if len(word) < 2:
return True
if word[0] != word[-1]:
return False
return is_palindrome(word[1:-1])
Since this is a rather simple (light) function this construction might not be the fastest because of the overhead of calling the function multiple times, but in other cases where the computation are more intensive it can be a very effective construction.
Just my two cents.
This question already has answers here:
Closed 12 years ago.
Possible Duplicate:
How to find positions of the list maximum?
A question from homework:
Define a function censor(words,nasty) that takes a list of words, and
replaces all the words appearing in nasty with the word CENSORED, and
returns the censored list of words.
>>> censor([’it’,’is’,’raining’], [’raining’])
[’it’,’is’,’CENSORED’]
I see solution like this:
find an index of nasty
replace words matching that index
with "CENSORED"
but i get stuck on finding the index..
You can find the index of any element of a list by using the .index method.
>>> l=['a','b','c']
>>> l.index('b')
1
Actually you don't have to operate with indexes here. Just iterate over words list and check if the word is listed in nasty. If it is append 'CENSORED' to the result list, else append the word itself.
Or you can involve list comprehension and conditional expression to get more elegant version:
Your approach might work, but it’s unnecessarily complicated.
Python allows a very simple syntax to check whether something is contained in a list:
censor = [ 'bugger', 'nickle' ]
word = 'bugger'
if word in censor: print 'CENSORED'
With that approach, simply walk over your list of words and test for each words whether it’s in the censor list.
To walk over your list of words, you can use the for loop. Since you might need to modify the current word, use an index, like so:
for index in len(words)):
print index, words[index]
Now all you need to do is put the two code fragments together.
You could use the handy built-in enumerate() function to step through the items in the list. For example:
def censor(words, nasty):
for i,word in enumerate(words):
if word...