This is homework but I'm not looking for a handout. Error messages haven't really been explained yet so I don't know how to fix this or why it's happening. I know it happens when I try to make s into an integer but I get a different error if I don't so I'm a little lost...
I've also tried looking at some of the other posts with similar problems but I'm very new to Python and I can't follow the explanations.
It's a pretty straightforward function, I think.
I've tried converting it to an integer to I can perform the range function on it but that doesn't seem to be working. The program is supposed to first put a space between the letters in "Blusson Hall" and add an additional space if there is already one there and finally print that design around the final product. Thanks for any help.
def spaced(s):
n = int (s)
for [i] in range (n):
if [i] != " ":
n == n+ [i] + " "
if [i] == " ":
n == n+ [i] + " "
print "-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-"
print ". ."
print "- " + str (n)+ " -"
print ". ."
print "-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-"
#- you write (5 marks) -#
###################
#- Tester's code -#
###################
spaced("Blusson Hall")
Your problem is that you are calling spaced with a non-numeric string and then trying to convert that to an integer:
>>> int("Blusson Hall")
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
ValueError: invalid literal for int() with base 10: 'Blusson Hall'
If you want a range based on the length of the string, you can use something like:
for i in range(len(s)):
as in:
>>> s = "Busson Hall"
>>> for i in range(len(s)):
... print i
...
0
1
2
3
4
5
6
7
8
9
10
And, as some extra assistance, you would use s[i] to get the i'th (zero being the first one, of course) character of s. In addition, you probably want to start with an empty string and then append individual characters to it (from the original string and whatever spaces you want added) to gradually build it up before returning it.
For example, this snippet duplicates every character with a colon between them:
>>> s = "paxdiablo"
>>> s2 = ""
>>> for i in range(len(s)):
... s2 = "%s%s:%s:" % (s2, s[i], s[i])
...
>>> print s2
p:p:a:a:x:x:d:d:i:i:a:a:b:b:l:l:o:o:
Short of writing the code for you (which, intelligently, you decided against asking for), that's probably all the help I can give (though feel free to ask any questions you want and I'll offer further advice).
i think i see the issue.
instead of
n = int(s)
try
n = len(s)
You can't convert a string to an integer, and that's what you try to do when you type:
n = int(s)
spaced only takes one argument, 's', and you pass in a string, then try to convert it to an integer. I think what you want is probably
n = len(s)
But really, you don't even need that. Since strings are iterable, you can just loop over it like:
for ch in s:
...do stuff here...
And if the index within s for each char is helpful/easier, enumerate() will do that for you:
for idx, ch in enumerate(s):
...do stuff here...
Just so you know, you don't actually need a for loop at all. Since strings are iterable and 'join()' takes an iterable as an argument, you can replace almost all of your code with this:
' '.join(s)
That looks odd if you haven't done much with Python before. I've created a string ' ', and join() is a method that all strings have available. Join takes some iterable object (like a list, or even another string) and puts the string that is the object of the join between each element of the iterable. So, in this case, it puts ' ' between each element of the string 's'.
Related
I want to use recursion to reverse a string in python so it displays the characters backwards (i.e "Hello" will become "olleh"/"o l l e h".
I wrote one that does it iteratively:
def Reverse( s ):
result = ""
n = 0
start = 0
while ( s[n:] != "" ):
while ( s[n:] != "" and s[n] != ' ' ):
n = n + 1
result = s[ start: n ] + " " + result
start = n
return result
But how exactly do I do this recursively? I am confused on this part, especially because I don't work with python and recursion much.
Any help would be appreciated.
def rreverse(s):
if s == "":
return s
else:
return rreverse(s[1:]) + s[0]
(Very few people do heavy recursive processing in Python, the language wasn't designed for it.)
To solve a problem recursively, find a trivial case that is easy to solve, and figure out how to get to that trivial case by breaking the problem down into simpler and simpler versions of itself.
What is the first thing you do in reversing a string? Literally the first thing? You get the last character of the string, right?
So the reverse of a string is the last character, followed by the reverse of everything but the last character, which is where the recursion comes in. The last character of a string can be written as x[-1] while everything but the last character is x[:-1].
Now, how do you "bottom out"? That is, what is the trivial case you can solve without recursion? One answer is the one-character string, which is the same forward and reversed. So if you get a one-character string, you are done.
But the empty string is even more trivial, and someone might actually pass that in to your function, so we should probably use that instead. A one-character string can, after all, also be broken down into the last character and everything but the last character; it's just that everything but the last character is the empty string. So if we handle the empty string by just returning it, we're set.
Put it all together and you get:
def backward(text):
if text == "":
return text
else:
return text[-1] + backward(text[:-1])
Or in one line:
backward = lambda t: t[-1] + backward(t[:-1]) if t else t
As others have pointed out, this is not the way you would usually do this in Python. An iterative solution is going to be faster, and using slicing to do it is going to be faster still.
Additionally, Python imposes a limit on stack size, and there's no tail call optimization, so a recursive solution would be limited to reversing strings of only about a thousand characters. You can increase Python's stack size, but there would still be a fixed limit, while other solutions can always handle a string of any length.
I just want to add some explanations based on Fred Foo's answer.
Let's say we have a string called 'abc', and we want to return its reverse which should be 'cba'.
def reverse(s):
if s == "":
return s
else:
return reverse(s[1:]) + s[0]
s = "abc"
print (reverse(s))
How this code works is that:
when we call the function
reverse('abc') #s = abc
=reverse('bc') + 'a' #s[1:] = bc s[0] = a
=reverse('c') + 'b' + 'a' #s[1:] = c s[0] = a
=reverse('') + 'c' + 'b' + 'a'
='cba'
If this isn't just a homework question and you're actually trying to reverse a string for some greater goal, just do s[::-1].
def reverse_string(s):
if s: return s[-1] + reverse_string(s[0:-1])
else: return s
or
def reverse_string(s):
return s[-1] + reverse_string(s[0:-1]) if s else s
I know it's too late to answer original question and there are multiple better ways which are answered here already. My answer is for documentation purpose in case someone is trying to implement tail recursion for string reversal.
def tail_rev(in_string,rev_string):
if in_string=='':
return rev_string
else:
rev_string+=in_string[-1]
return tail_rev(in_string[:-1],rev_string)
in_string=input("Enter String: ")
rev_string=tail_rev(in_string,'')
print(f"Reverse of {in_string} is {rev_string}")
s = input("Enter your string: ")
def rev(s):
if len(s) == 1:
print(s[0])
exit()
else:
#print the last char in string
#end="" prints all chars in string on same line
print(s[-1], end="")
"""Next line replaces whole string with same
string, but with 1 char less"""
return rev(s.replace(s, s[:-1]))
rev(s)
if you do not want to return response than you can use this solution. This question is part of LeetCode.
class Solution:
i = 0
def reverseString(self, s: List[str]) -> None:
"""
Do not return anything, modify s in-place instead.
"""
if self.i >= (len(s)//2):
return
s[self.i], s[len(s)-self.i-1] = s[len(s)-self.i-1], s[self.i]
self.i += 1
self.reverseString(s)
I´ve searched for other "string index out of range" cases, but they were not useful for me, so I wanted to search for help here.
The program has to do this: "Write a function kth_word(s, k) that given a string s and an integer k≥ 1 returns the kth word in string s. If s has less than k words it returns the empty string. We assume all characters of s are letters and spaces. Warning: do not use the split string method."
Here is my code:
def kth_word(s, k):
new =""
word_count = 0
for i in range(0, len(s)):
if s[i] == " " and s[i+1] != " ":
word_count+=1
#try to find how many characters to print until the space
if word_count == k-1:
while i!= " " and i<=len(s): #if it is changed to i<len(s), the output is strange and wrong
new+=s[i]
i=i+1
print(new) #check how new is doing, normally works good
return new
print(kth_word('Alea iacta est', 2))
(I tried my best to implement the code in a right way, but i do not know how)
And depending on the place where you live return new it gives or an error or just an empty answer
You iterate from 0 to len(s)-1 in your first for loop, but you're addressing i+1 which, on the last iteration, is len(s).
s[len(s)] is an IndexError -- it is out of bounds.
Additionally your while loop is off-by-one.
while i!= " " and i<=len(s):
# do something referencing s[i]
Your first condition makes no sense (i is a number, how could it be " "?) and your second introduces the same off-by-one error as above, where i is maximally len(s) and s[len(s)] is an error.
Your logic is a bit off here, too, since you're wrapping this inside the for loop which is already referencing i. This appears to be a takewhile loop, but isn't really doing that.
Warning: do not use the split string method.
So groupby / islice from itertools should work:
from itertools import groupby, islice
def kth_word(s, k):
g = (j for i, j in groupby(s, key=lambda x: x==' ') if not i)
return ''.join(next(islice(g, k-1, k), ''))
words = 'Alea iacta est'
res = kth_word(words, 2) # 'est'
We handle StopIteration errors by setting the optional parameter in next to ''.
You're not allowed to use str.split. If you could, the answer would just be:
def kth_word(s, k):
return s.split()[k]
But if you could write a function that does the same thing str.split does, you could call that instead. And that would certainly show that you understand everything the assignment was testing for—how to loop over strings, and do character-by-character operations, and so on.
You can write a version with only the features of Python usually taught in the first week:
def split(s):
words = []
current = ''
for ch in s:
if ch.isspace():
if current:
words.append(current)
current = ''
else:
current += ch
if current:
words.append(current)
return words
If you know additional Python features, you can improve it in a few ways:
Build current as a list instead of a str and ''.join it.
Change those append calls to yield so it splits the string lazily (even better than str.split).
Use str.find or str.index or re.search to find the next space instead of searching character by character.
Abstract out the space-finding part into a general-purpose generator—or, once you realize what you want, find that function in itertools.
Add all of the features we're missing from str.split, like the ability to pass a custom delimiter instead of breaking on any whitespace.
But I think even the basic version—assuming you understand it and can explain how it works—ought to be enough to get an A on the assignment.
And, more importantly, you're practicing the best way to solve problems: reduce them to simpler problems. split is actually easier to write than kth_word, but once you write split, kth_word becomes trivial.
You actually have at least five problems here, and you need to fix all of them.
First, as pointed out by Adam Smith, this is wrong:
for i in range(0, len(s)):
if s[i] == " " and s[i+1] != " ":
This loops with i over all the values up to but not including len(s), which is good, but then, if s[i] is a space, it tries to access s[i+1]. So, if your string ended with a space, you would get an IndexError here.
Second, as ggorlen pointed out in a comment, this is wrong:
while i!= " " and i<=len(s):
new+=s[i[]
When i == len(s), you're going to try to access s[i], which will be an IndexError. In fact, this is the IndexError you're seeing in your example.
You seem to realize that's a problem, but refuse to fix it, based on this comment:
#if it is changed to i<len(s), the output is strange and wrong
Yes, the output is strange and wrong, but that's because fixing this bug means that, instead of an IndexError, you hit the other bugs in your code. It's not causing those bugs.
Next, you need to return new right after doing the inner loop, rather than after the outer loop. Otherwise, you add all of the remaining words rather than just the first one, and you add them over and over, once per character, instead of just adding them once.
You may have been expecting that doing that i=i+1 would affect the loop variable and skip over the rest of the word, but (a) it won't; the next time through the for it just reassigns i to the next value, and (b) that wouldn't help anyway, because you're only advancing i to the next space, not to the end of the string.
Also, you're counting words at the space, but then you're iterating from that space until the next one. Which means (except for the first word) you're going to include that space as part of the word. So, you need to do an i += 1 before the while loop.
Although it would probably be a lot more readable to not try to reuse the same variable i, and also to use for instead of while.
Also, your inner loop should be checking s[i] != " ", not i!=" ". Obviously the index, being a number, will never equal a space character.
Without the previous fix, this would mean you output iacta est
with an extra space before it—but with the previous fix, it means you output nothing instead of iacta.
Once you fix all of these problems, your code works:
def kth_word(s, k):
word_count = 0
for i in range(0, len(s) - 1):
if s[i] == " " and s[i+1] != " ":
word_count+=1
#try to find how many characters to print until the space
if word_count == k-1:
new =""
j = i+1
while j < len(s) and s[j] != " ":
new+=s[j]
j = j+1
print(new) #check how new is doing, normally works good
return new
Well, you still have a problem with the first word, but I'll leave it to you to find and fix that one.
Your use of the variable 'i' in both the for loop and the while loop was causing problems. using a new variable, 'n', for the while loop and changing the condition to n < len(s) fixes the problem. Also, some other parts of your code required changing because either they were pointless or not compatible with more than 2 words. Here is the fully changed code. It is explained further down:
def kth_word(s, k):
new = ""
word_count = 0
n = 0
for i in range(0, len(s) - 1):
if s[i] == " " and s[i + 1] != " ":
word_count += 1
#try to find how many characters to print until the space
if word_count < k:
while n < len(s): #if it is changed to i<len(s), the output is strange and wrong
new+=s[n]
n += 1
print(new) #check how new is doing, normally works good
return new
print(kth_word('Alea iacta est', 2))
Explanation:
As said in Adam Smith's answer, 'i' is a number and will never be equal to ' '. That part of the code was removed because it is always true.
I have changed i = i + 1 to i += 1. It won't make much difference here, but this will help you later when you use longer variable names. It can also be used to append text to strings.
I have also declared 'n' for later use and changed for i in range(0, len(s)): to for i in range(0, len(s) - 1): so that the for loop can't go out of range either.
if word_count == k-1: was changed to if word_count < k: for compatibility for more words, because the former code only went to the while loop when it was up to the second-last word.
And finally, spaces were added for better readability (This will also help you later).
def main():
string = raw_input("string:")
pattern = raw_input("pattern:")
end = len(string)
insertPattern(string,pattern)
def insertPattern(string,pattern):
end= len(string)-1
print "Iterative:",
for x in range(end):
if x == end:
print string[x]
if x < end:
print string[x]+pattern,
main()
I'd like this to output
Instead it's outputting
How would I modify the code to fix this? Assignment requires that I do this without lists or join.
You've got three problems here.
First, the reason you're getting that Iterative: at the beginning is because you explicitly asked for it with this line:
print "Iterative:",
Just take it out.
The reason you're getting spaces after each * is a bit trickier. The print statement's "magic comma" always prints a space. There's no way around that. So, what you have to do is not use the print statement's magic comma.
There are a few options:
Use the more-powerful print function from Python 3.x, which you can borrow in 2.7 with a __future__ statement. You can pass any separator you want to replace the space, even the empty string.
Use sys.stdout.write instead of print; that way you get neither newlines nor spaces unless you write them explicitly.
Build up the string as you go along, and then print the whole thing at the end.
The last one is the most general solution (and also leads to lots of other useful possibilities, like returning or storing the built-up string), so I'll show that:
def insertPattern(string,pattern):
result = ''
end= len(string)-1
for x in range(end):
if x == end:
result += string[x]
if x < end:
result += string[x]+pattern
print result
Finally, the extra * at the end is because x == end can never be true. range(end) gives you all the numbers up to, but not including end.
What you probably wanted was end = len(string), and then if x == end-1.
But you can simplify this quite a bit. The only reason you need x is to get string[x], and to distinguish either the first or last value from the others (so you know not to add an extra * either before the first or after the last). You can solve the last one with a flag, or by just treating the first one special. And then, you can just iterate over string itself, instead of over its indices:
def insertPattern(string,pattern):
result = string[0]
for ch in string[1:]:
result += pattern + ch
print result
And once you've done that, you may realize that this is almost identical to what the str.join method does, so you can just use that:
def insertPattern(string,pattern):
print pattern.join(string)
I'm absolutely terrible at Python and my Computer Programming class ends in two days (thank god), but I am having the hardest time figuring out what is probably the easiest code ever.
The instructions to my assignment state, "Write a program which reads in text until a '!' is found. Use an array of integers subscripted by the letters 'A' through 'Z'."
From what i have done so far:
msg = input("What is your message? ")
msg = msg.upper()
int_array = [0] * 26
for alph in range (65, 91):
char = chr(alph)
print(char)
(int_array[char])
any help would be greatly appreciated! thanks!
EDIT: This is the full assignment:
Write a program which reads in text from the keyboard until a ('!') is found.
Using an array of integers subscripted by the letters 'A' through 'Z', count the number occurrences of each letter (regardless of whether it is upper or lower case). In a separate counter, also count the total number of "other" characters ('.', '?', ' ', '2', etc.).
Print out the count for each letter found. Also, print the count of the non-letter characters.
By inspecting the array, print out the count of the number of vowels, and the number of consonants.
Print out which letter was found the most times. (Note there may be more than one letter which has the maximum count attached to it.) Print out which letter (or letters) was found the least number of times, but make certain to exclude letters which were not found at all.
UPDATE:
I have gotten this far with my code
msg = input("What is your message? ")
print ()
num_alpha = 26
int_array = [0] * num_alpha
for alpha in range(num_alpha):
int_array[alpha] = chr(alpha + 65)
print(int_array[alpha], end = "")
print()
lett = 0
otherch = 0
num_vowels = 0
num_consanants = 0
count_character = [0] * 100000
length = len(msg)
for character in msg.upper():
if character == "!":
print("lett =", lett)
print("other char = ", otherch)
print("num_vowels = ", num_vowels)
print("num_consanants = ", num_consanants)
elif character < "A" or letter > "Z":
otherch = otherch + 1
count_character[ord(character)] = count_character[ord(character)] + 1
else:
lett = lett + 1
count_character[ord(character)] = count_character[ord(character)] + 1
for character in msg:
print("character", character, "appeared" , count_character[ord(character)] , "times")
it's obviously not finished yet, but every time i print the last print statement, it says that each character appeared 0 times. can anybody help?
You're going to need to get clarification on this, because there's no such thing as "an array of integers subscripted by the letters 'A' through 'Z'" in Python.
Possible interpretations that I can think of:
It's supposed to be a dictionary rather than an array. Python dictionaries are similar to lists (the Python datatype that is roughly equivalent to "arrays" in other languages), but they can be subscripted by strings, whereas lists can be subscripted only by integers. This way, you can store an integer to be associated with each letter. This is how most Python programmers would generally do something like this.
You're supposed to use parallel lists. You can do this by making two lists of 26 elements each, one containing the letters 'A' through 'Z' and one containing integers. For each letter, you could then use the list.index method to find the index in the first list where that letter is, then look up that index in the second list. (In theory, you wouldn't really need the first list, since Python strings are like lists in that they can be subscripted with integers and support the index method. So you could use the string 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' instead of a list. Or you could use the ord function, which is the inverse of the chr function. But I don't know if you're supposed to use these features.)
I'm not 100% sure the following is right because I agree with the others that the assignment description is wonky. It looks like a C-based homework assignment lazily ported to Python. That said:
In principle rather than hardcoding the bounds of the alphabet I'd go with ord('A') and ord('Z')+1, so that I can say something like alphabet = list(range(ord('A'), ord('Z')+1))
Renaming int_array to counter might make it more obvious what you need to do in your inner loop (keeping in mind that you're using the letters as your indices. Or rather, you'd need something more like ord(letter)-ord('A') as your indices)
You don't want to loop over the alphabet; you want to loop over the input.
count should be initialized to [0]*27 to track "other" values. You can increment counter[-1] for non-alphabetic characters.
Your final value is chr of counter.index(max(counter)). You may find it more straightforward, or your teacher may find it more acceptable, to just write a for loop.
I have the following problem: I would like to write a function in Python which, given a string, returns a string where every group of two characters is swapped.
For example given "ABCDEF" it returns "BADCFE".
The length of the string would be guaranteed to be an even number.
Can you help me how to do it in Python?
To add another option:
>>> s = 'abcdefghijkl'
>>> ''.join([c[1] + c[0] for c in zip(s[::2], s[1::2])])
'badcfehgjilk'
import re
print re.sub(r'(.)(.)', r'\2\1', "ABCDEF")
from itertools import chain, izip_longest
''.join(chain.from_iterable(izip_longest(s[1::2], s[::2], fillvalue = '')))
You can also use islices instead of regular slices if you have very large strings or just want to avoid the copying.
Works for odd length strings even though that's not a requirement of the question.
While the above solutions do work, there is a very simple solution shall we say in "layman's" terms. Someone still learning python and string's can use the other answers but they don't really understand how they work or what each part of the code is doing without a full explanation by the poster as opposed to "this works". The following executes the swapping of every second character in a string and is easy for beginners to understand how it works.
It is simply iterating through the string (any length) by two's (starting from 0 and finding every second character) and then creating a new string (swapped_pair) by adding the current index + 1 (second character) and then the actual index (first character), e.g., index 1 is put at index 0 and then index 0 is put at index 1 and this repeats through iteration of string.
Also added code to ensure string is of even length as it only works for even length.
string = "abcdefghijklmnopqrstuvwxyz123"
# use this prior to below iteration if string needs to be even but is possibly odd
if len(string) % 2 != 0:
string = string[:-1]
# iteration to swap every second character in string
swapped_pair = ""
for i in range(0, len(string), 2):
swapped_pair += (string[i + 1] + string[i])
# use this after above iteration for any even or odd length of strings
if len(swapped_pair) % 2 != 0:
swapped_adj += swapped_pair[-1]
print(swapped_pair)
badcfehgjilknmporqtsvuxwzy21 # output if the "needs to be even" code used
badcfehgjilknmporqtsvuxwzy213 # output if the "even or odd" code used
Here's a nifty solution:
def swapem (s):
if len(s) < 2: return s
return "%s%s%s"%(s[1], s[0], swapem (s[2:]))
for str in ("", "a", "ab", "abcdefgh", "abcdefghi"):
print "[%s] -> [%s]"%(str, swapem (str))
though possibly not suitable for large strings :-)
Output is:
[] -> []
[a] -> [a]
[ab] -> [ba]
[abcdefgh] -> [badcfehg]
[abcdefghi] -> [badcfehgi]
If you prefer one-liners:
''.join(reduce(lambda x,y: x+y,[[s[1+(x<<1)],s[x<<1]] for x in range(0,len(s)>>1)]))
Here's a another simple solution:
"".join([(s[i:i+2])[::-1]for i in range(0,len(s),2)])