Your answers have helped me a lot before, but now I'm stuck on a problem that I can't find the answer to. I'm currently at the start of teaching myself Python, and I've come across an exercise I can't figure out. I need to print each of the characters of a string on a new line in reverse order, with the number of spaces before each character being equal to the character's position in the string. Ideally, this would use a for loop.
I can print each character on a new line and in reverse order fine, but my issue is that when I reverse the string, it reverses the position of each of the characters: e.g. in the string 'dog', 'd' is in position 1, but reversed, is in position 3. I'd like to print the number of spaces multiplied by the original position of the string, rather than after it has been reversed.
This is what I have so far (apologies for any dodgy code).
def print_reverse(text):
x = 0
spc = ' '
for i in text[::-1]:
print(spc * x, i)
x += 1
print_reverse('dog')
Expected results:
g
o
d
Actual results:
g
o
d
The issue is initially x is 0. Instead you can try decreasing x from length of text:
def print_reverse(text):
x = len(text)
spc = ' '
for i in text[::-1]:
print(spc * x, i)
x -= 1
print_reverse('dog')
def print_reverse(text):
x = len(text)
spc = ' '
for i in text[::-1]:
print(spc * x, i)
x -= 1
This works
def print_reverse(text):
x = len(text)
spc = ' '
for i in text[::-1]:
print(spc * x, i)
x -= 1
In the iteration, you iterate like 0,1,2,3,.... You want decreasing spaces (...3,2,1,0), therefore try for example:
def print_reverse(text):
x = 0
spc = ' '
for i in text[::-1]:
print((len(text) - x)*spc,
print(i)
x += 1
Here you take the length of the string and substract your loop index. Same idea as the other stated solution by the user student, but slightly different implementation :)
You can accomplish this in a couple lines with a little bit of generator comprehension and enumerate:
def print_reverse(text):
for line in (' ' * (len(word)-i) + c for i, c in enumerate(text[::-1])):
print(line)
enumerate returns each list item, as well as it's position in a list (or in this case a string).
So enumerate('dog') will return:
((0, 'd'), (1, 'o'), (2, 'g'))
If you subtract the position from the total length of the word (len(word)-i), you'll get the number of spaces you need in front of your leter.
This answer also uses a generator expression, which is easy way to apply the same expression for each item in a list.
Finally, text[::-1] gives you a reversed list (you could also do reversed(text).
Related
I need to split the string from the end.
For example, I have
word = '3640000'
And it is easy to split it from the begin of the string using list generator and .join method:
word = ' '.join([word[i:i + 3] for i in range(0, len(word), 3)])
In this case I get result: '364 000 0'
but I need get: "3 640 000"
How can I solve this task?
I tried something like this, but it is not working for me if a word is not divisible by 3 without remainder
list1 = []
for i in range(len(word) - 1, -1, -3):
print(word[i-2:i+1])
list1.append(word[i-2:i+1])
list1.reverse()
It's a bit hacky, we can use Python's string formatting to do the grouping, then replace the separator (Python only allows "," and "_" as grouping characters).
>>> w = '3640000'
>>> f'{int(w):,d}'.replace(',', ' ')
'3 640 000'
This is somewhat inefficient, but based on what you did initially, you can reverse the word and then split/join with spaces, then reverse it back:
word = '3640000'
word = word[::-1]
word = ' '.join([word[i:i + 3] for i in range(0, len(word), 3)])
print(word[::-1])
Where n is 3 in this example.
If you take the first part that is irregular first, it allows you to process the remaining part from front to back without hacks as before.
Use the modulo operator % to calculate the required length for the first part:
first_length = len(word) % 3
if first_length > 0:
result = word[:first_length] + ' '
else:
result = ''
result += ' '.join(word[i:i+3] for i in range(first_length, len(word), 3))
This can be made somewhat more generic and elegant by writing a generator function:
def split_from_right(word, n):
first_length = len(word) % n
if first_length > 0:
yield word[:first_length]
for i in range(first_length, len(word), n):
yield word[i:i + n]
result = ' '.join(split_from_right(word, 3))
I wanna write a function that takes a string, s, and an int, x. It should return a new string where every xth character (starting from zero) is now followed by an '*'.
So far I've tried this code:
def string_chunks(string, x):
"""
>>> string_chunks("Once upon a time, in a land far, far away", 5)
'O*nce u*pon a* time*, in *a lan*d far*, far* away*'
"""
for ch in string:
return ch + "*"
but I am very stuck and am unable to make it work.
I would appreciate any help. If you provide an answer, it would be nice if you could comment the code also.
Turn it into a list and every nth index append a '*', then join it back to a string.
def string_chunks(string, x):
string = list(string)
for i in range(0, len(string)-1, 5):
string[i] += '*'
return ''.join(string)
Using a new string instead of a list
I thought it could be easier using a new string (ns) instead of a list to be joined, just adding each character of the original string (text = s) with a '' after each multiple of the interval x (checked with the if multiple_of_x. To check if the n (index of the character of s) is a multiple I used n % x == 0 that is equal to zero only for multiple of x (ex.: 5 10 15, because 5 % 5 = 0, 15 % 5 = 0.... and so on). If the result of n % x in not 0, it will add only the character without the ''.
def string_chunks(s,x=5):
ns = ""
for n,ch in enumerate(s):
multiple_of_x = (n % x == 0)
ns += ch + "*" if multiple_of_x else ch
return ns
text = "Once upon a time, in a land far, far away"
print(string_chunks(text))
Using a list
It can be done this way too.
def string_chunks(s,x=5):
ns = []
for n,ch in enumerate(s):
multiple_of_interval = (n % x == 0)
ns.append(ch + "*") if multiple_of_interval else ns.append(ch)
ns = "".join(ns)
return ns
text = "Once upon a time, in a land far, far away"
print(string_chunks(text))
Output
O*nce u*pon a* time*, in *a lan*d far*, far* away*
Currently you do this:
for ch in string:
return ch + "*"
This immediately exists the function. Instead, you want to create the whole string by doing something like this:
chunked_text = chunked_text + ch + "*"
and only after iterating over the whole string you want to return it.
try this
def string_chunks(string, x):
"""
>>>
'O*nce u*pon a* time*, in *a lan*d far*, far* away*'
"""
count = 0
newstring = []
for ch in string:
count = count + 1
if count == x:
newstring.append("*")
newstring.append(ch)
count = 0
else:
newstring.append(ch)
return("".join(str(x) for x in newstring))
output_s = string_chunks("Once upon a time, in a land far, far away", 5)
print output_s
Output:
Once* upon* a ti*me, i*n a l*and f*ar, f*ar aw*ay
The wording of my question was not polite to the search feature on the site, so I apologize should someone feel this is a duplicate question, but I must ask anyway.
Working in Python 3.6.1, my goal is to find a substring of letters in a string that are in alphabetical order and if that substring of letters is the longest substring of letters in alphabetical order (aa would be considered alphabetical order), then print out the string. I have not gotten entirely close to the solution but I'm making progress; however, this came up and I'm confounded by it being completely new to Python. My question is, why is this valid:
s = 'hijkkpdgijklmnopqqrs'
n = len(s)
i = 0
a = 0
for i in range(n-2):
if s[i] <= s[i+1]:
a = s[i+1]
i = s[i+2]
a = i + a
print(a)
And yet this is not:
s = 'hijkkpdgijklmnopqqrs'
n = len(s)
i = 0
a = 0
b = ''
for i in range(n-2):
if s[i] <= s[i+1]:
b = a + i
a = s[i+1]
i = s[i+2]
a = a + i
print(b)
When the latter code is run, I receive the error:
Traceback (most recent call last):
File "C:\Users\spect\Desktop\newjackcity.py", line 14, in <module>
b = a + i
TypeError: must be str, not int
What I am ultimately trying to do is to 'index in' to the string s, compare the zeroth element to the zeroth+1 element and if s[I] < s[I+1], I want to concatenate the two into my variable a for later printing. Because when I do this, a only prints out two letters in the string. I thought, well initialize the variable first so that a and i can be incremented, then added into a for comparison purposes, and b for printing.
I see now that I'm only going through n-2 iterations (in order to compare the second to last letter to n-1 so the logic is flawed, but I still don't understand the error of why all of a sudden binding a+i to a variable b will produce a str/int error? In my view saying s[i]; etc. is pulling out the elements as a string and this to me is proven in the fact if I run the first set of code, I get the output:
sr
>>>
In both for loops, you use i as the loop variable, so it starts as an int.
In the first version, you reassign i to a string, then add.
for i in range(n-2):
# here i is an int, something between 0 and n-2
if s[i] <= s[i+1]:
a = s[i+1] # a is a string...
i = s[i+2] # now you change i to a string
a = i + a # string + string: OK!
In the second version you try to add i first:
for i in range(n-2):
# here i is an int, something between 0 and n-2
if s[i] <= s[i+1]:
b = a + i # string + int, can't do it...
a = s[i+1]
i = s[i+2]
a = a + i
You will have an easier time debugging your code if you pick more meaningful names.
edit: here is my cleaned up version of your code:
s = 'hijkkpdgijklmnopqqrs'
# i = 0 isn't needed, range starts at 0
# the first character is always 'alphabetical'
alph_substr = s[0]
# range(1,n) is [1,2, ..., n-1]
for i in range(1, len(s)):
if s[i-1] <= s[i]:
alph_substr = alph_substr + s[i]
else:
# we have to start over, since we're not alphabetical anymore
print(alph_substr)
alph_substr = s[i]
print(alph_substr)
This question already has answers here:
Understanding slicing
(38 answers)
Closed 7 years ago.
I'm a new programmer and I'm having a lot of trouble understanding for loops and while loops. In what situations would I know to use a for loop and in what situations would I know to use a while loop?
Also, could you explain to me what these 2 codes mean? I have a a lot of confusion.
1 function:
def every_nth_character(s, n):
""" (str, int) -> str
Precondition: n > 0
Return a string that contains every nth character from s, starting at index 0.
>>> every_nth_character('Computer Science', 3)
'CpeSee'
"""
result = ''
i = 0
while i < len(s):
result = result + s[i]
i = i + n
return result
****What does s[i] mean?****
2nd function:
def find_letter_n_times(s, letter, n):
""" (str, str, int) -> str
Precondition: letter occurs at least n times in s
Return the smallest substring of s starting from index 0 that contains
n occurrences of letter.
>>> find_letter_n_times('Computer Science', 'e', 2)
'Computer Scie'
"""
i = 0
count = 0
while count < n:
if s[i] == letter:
count = count + 1
i = i + 1
return s[:i]
what does s[i] and s[:i] mean??
S is a list of characters 'Computer Science'["C","o","m","p"...], and i is the indexposition for each item/character in the list S, so in your case you've stated that your loop counts each third(3) item in S as long as there are items in S, that is, S[i] = [C], S[i]=[p], S=[e], S[i]= C, S[i]=p, where i is each third element in S.
In the second case you've defined i as a variable with value 0, after each loop i increases with +1, i = i + 1, and [:i] means return elements in S up to the latest looped slice, for instance "Computer Scie" + one additional loop would give you "Computer Scien" (i = 9 (the current range of S/number looped characters in S) -> i+1 (increased by +1) -> i=10 (i = 10, S[i]=10 means the first 10 indexpositions/charachters in S]
Your first question about differencies in while and for loops is completely answered here.
Strings and indexing:
Variable s holds a string value. As you may have noticed, it has been submitted as an argument for every_nth_character(s, n) function.
Now every letter in a string is in some position and that position is called index. indexing starts from 0. So if we have a string s containing value 'foo123', it's first character s[0] is 'f' and the last character s[5] = 3.
String can be cutted and sliced using ':' in the index field. Referring to the previous example, we have determined string s. Now you can take only first three characters of that string by using s[:3] and get 'foo' as a result. Read more about it here
Loops:
While and for loops start over and over again until they reach the limit you have determined.
For example:
x = 0
while x < 5:
print x
x = x + 1
prints numbers from 0 to 4. Variable x increases +1 at every single run and the loop ends when x reaches value 5.
Get familiar with Python documentation page, it will help you a lot in future especially in basic things. Google search: Python (your-python-version) documentation
I am trying to learn python and get good at algorithms. This is my first language.
for example: take "baggage" and sort into "aabeggg"
string = "baggage"
count = [0] * len(string)
for x in string:
num_value = ord(x)
count[num_value] += 1
I think the above is a start...but I'm not really sort how to go about it.
collections.Counter is a great way to solve this, but here is a way to get you a bit further in the direction you are heading
string = "baggage"
count = [0] * 256 # This should be big enough to hold counters for every 8 bit character
for x in string:
num_value = ord(x)
count[num_value] += 1
for i in range(256): # loop through all the possible 8 numbers
if count[i]:
print chr(i)*count[i]
# you can join them all back into a string like this
newstr = ''.join(chr(i)*c for i,c in enumerate(count))
Let's take a look at your code here.
string = "baggage"
count = [0] * len(string)
# count is now [0,0,0,0,0,0,0]
for x in string:
num_value = ord(x)
# ord(x) gives you the ascii number value of a character x
# So for example ord('b') = 98
count[num_value] += 1
# error here since count[98] isn't set.
Pablo gave you a quick solution. I'll write out one using a dictionary that might be more explicit.
string = "baggage"
count = {}
for c in string:
if c in count:
count[c] += 1
else:
count[c] = 1
print ''.join(count[c]*c for c in sorted(count))
Use a collections.Counter:
from collections import Counter
string = 'baggage'
c = Counter(string)
result = ''.join(c[x]*x for x in sorted(c.keys()))
It works as follows:
Counter does exactly what you were trying to achieve with count[num_value] += 1
sorted(c.keys()) gives you the characters in sorted order
c[x]*x is a string made up of c[x] copies of the char x
''.join( ... ) joins each of the resulting strings into a single one