For Loop Not Iterating Expected Amount of Time - python

I'm attempting to write some code as practice for python. After the user inputs a string and a number that is a factor of the length of the string, the output should be the reverse of the string split up into segments equal to the inputted number. My issue is that the output is cut short, which I believe is a problem caused by the condition of my for loop.
def reverse_and_slice(string, k):
i=0
n=len(string)
j=0
revstring=string[::-1]
finalstring=''
for i in range(n//k):
finalstring+=revstring[j:(i+1)*k] + ' '
j+=(i+1)*k
i+=1
print(finalstring)
I am trying to accomplish this using a for loop. 123456789 should print as 987 654 321. However, it is currently printing as 987 654, without the last three digits. Longer inputs are similarly cut short with only two segments of length k.

Your loop iterate correct amount of times. You can simply check it by printing i in the loop. Problem is with j. In the last iteration, it is equal to 9, so revstring[9:9] is empty. And this is caused by + before =: j+=(i+1)*k You are incrementing j instead of changing value.
def reverse_and_slice(string, k):
i=0
n=len(string)
j=0
revstring=string[::-1]
finalstring=''
for i in range(n//k):
finalstring+=revstring[j:(i+1)*k] + ' '
j = (i+1)*k
i+=1 # this line is also not needed
print(finalstring)

Related

Why am I not getting desired output in this code

I want to write a code for this question:
write a code which creates a new number 'n2' which consists reverse order of digits of a number 'n' which divides it without any remainder for example if input is 122
it will print 221 because 1,2,2 can divide 122 without any remainder another example is 172336 here 1,2,3,3,6 can divide it without any remainder so the output should be 63321(reverse order).
my code is:
n = str(input())
x = ""
z = 0
for z in range(len(n)):
if int(n)%int(n[z])==0:
x = n[z] + ""
else:
n.replace(n[z],"")
z = z+1
print(x[::-2])
if I input the number 122 here i get the output 2 but i should be getiing output of 221 why.
The reason why you are not getting the desired output in this code is because of several logical and syntactical errors in your code. Here are some of them:
You are using x = n[z] + "" to append the digits that divide n without any remainder, but this will overwrite the previous value of x every time. You should use x = x + n[z] instead.
You are using n.replace(n[z],"") to remove the digits that do not divide n without any remainder, but this will not modify the original value of n, since strings are immutable in Python. You should assign the result of n.replace(n[z],"") to a new variable, or use a different approach to filter out the unwanted digits.
You are using z = z+1 to increment the loop variable, but this is unnecessary and redundant, since the for loop already does that for you. You can remove this line.
You are using print(x[::-2]) to print the reversed value of x, but this will skip every other digit, since the negative step of -2 means you are slicing the string from the end to the beginning with a step of 2. You should use print(x[::-1]) instead, which will reverse the whole string. A possible corrected version of your code is:
python
n = str(input())
x = ""
for z in range(len(n)):
if int(n)%int(n[z])==0:
x = x + n[z]
print(x[::-1])
This code will print the reversed order of the digits of n that divide it without any remainder, as expected. For example, if the input is 122, the output will be 221.
The code works by iterating over each digit of the input number n, which is converted to a string for convenience. For each digit, it checks if it divides n without any remainder, using the modulo operator %. If it does, it appends the digit to the end of the string x, using the + operator. If it does not, it ignores the digit. After the loop, it prints the reversed value of x, using the slicing notation [::-1], which means start from the end and go backwards until the beginning.
This should do the Trick
num = input()
new_num = ""
for i in num:
if int(num)%int(i) == 0:
new_num += i
print(new_num[::-1])

Why is my code giving memory error?

I am making a program where I can count the number of a in a string. This is my Code:
def repeatedString(s, n):
converged = s*n
got_it = converged[0:n]
count = 0
for x in got_it:
if "a" in x:
count += 1
return count
s = input()
n = int(input())
result = repeatedString(s, n)
print(result)
The variable s is where the string is entered, and variable n is for upto how long the string will repeat. My Code works OK, but for some reason when I give a bigger integer, it falls apart and gives me a Memory Error. For example, my input is:
a
1000000000000
It gives me this error:
Traceback (most recent call last):
File "programs.py", line 11, in <module>
result = repeatedString(s, n)
File "programs.py", line 2, in repeatedString
converged = s*n
MemoryError
How can I fix this Memory Error? If there's a better way to do it, it would also be helpful.
The problem with your code is where you do converged = s*n. In that line, you are asking the program to take the string s and allocate enough memory to fit the number of bytes in s * n, which, as you have seen, has a limit because your computer has a finite amount of free memory available (most modern-day computers only carry 4 - 16 gigabytes of RAM).
One way you can fix the memory error is by exploiting one aspect of your function - you are simply checking how many "a"'s fit in a string s repeated up to a length of n. So, instead of doing converged = s*n and subsequent modifications that require a lot of memory to store such a large string, you can instead use simple math to get the answer you are looking for.
Also, another optimization you could do is that you do not have to convert your string into an array to loop over it. Instead of doing for x in got_it, you could do for c in s.
Here is a working example of how you can accomplish what you need:
import math
def repeatedString(s, n):
if len(s) == 0:
return 0
reps = float(n) / len(s)
count = 0
for c in s:
if c == "a":
count += 1
# After testing the code, it turns out that Python does not play nicely
# with rounding UP from 0.5, so this is necessary to get the correct answer
result = count * reps
if result - math.floor(result) < 0.5:
return math.floor(result)
return math.ceil(result)
s = input()
n = int(input())
result = repeatedString(s, n)
print(result)
this program
takes a input string named s
repeats this string concatenated n times
takes only the first n charactes in the concatenated
counts how many times the letter "a" appears
you
you give the string "a"
you give the number 1000000000000
then the program should count and return 1000000000000
memmory problem
I guess this string with 1000000000000 letters "a" is too big
for the type in the python language
or for the computer memmory
the way it is
given that the program searches for the fixed occurrences of letter "a"
you passed exactly the letter "a" and the number 1000000000000
the better way is that it's not necessary a program
if you want to know how many times there is the letter "a"
in a string with 1000000000000 letters "a"
the answer is obviously 1000000000000
extra:
it would be complicated:
to rewrite the program
to search for a pattern
given as input parameter,
with variable length
AND
avoid the memmory problem
I guess I would write a program that
concatenates the "s" input just to have a length bigger than the searched pattern (if already not is)
check if the pattern occurs
after that multiply by "n"
ajust the how many times it will 'fit' in the final
one-line solution: find no of 'a' in string s, multiply with floor division of no.of repetition with the length of s + finding 'a' in the remaining length of s
s.count("a") * (n // len(s)) + s[:n % len(s)].count("a")
Thanks for all the help guys, I managed to solve the problem by handling the exception using try and except MemoryError

Python optimizing loops for checking number of anagrams

i am trying to solve a question that provides a string as input and gives the number of anagrams possible as output. this can be solved using dictionaries but i could only think in terms of for loops and string indices.
count = 0
for i in range(1,len(s)):
for j in range(0,len(s)):
for k in range(j+1,len(s)):
if(k+i>len(s)):
continue
# print(list(s[j:j+i]),list(s[k:k+i]),j,j+i,k,k+i)
if(sorted(list(s[j:j+i]))==sorted(list(s[k:k+i]))):
count +=1
return count
i have coded this far and tried for optimization with k+i. can someone tell me other techniques to optimize the code without losing the logic. the code keeps getting terminated due to time-out for larger strings.should i replace sorted function with something else.
The number of anagrams if each letter was unique would be n! with n as the length of the string (e.g. law has 3!=6). If there a given letter is repeated, say, twice (e.g. wall), then you have twice as many answers as you should (since things like w-(second l)-(first l)-a are actually indistinguishable from things like w-(first l)-(second l)-a). It turns out that if a letter is repeated k times (k is 2 for the letter "l" in wall), n! overcounts by a factor of k!. This is true for each repeated letter.
So to get the number of anagrams, you can do:
letter_counts = get_letter_counts(s) #returns something like [1, 1, 2] when given wall, since there is one w, one a, two ls
n_anagrams = factorial(len(s))
#account for overcounts
for letter_count in letter_counts:
n_anagrams /= factorial(letter_count)
return n_anagrams
Implementing factorial and get_letter_counts left as an excercise for the reader :-) . Note: Be careful to consider that repeated letters can show up more than once, and not always next to each other. Ex: "aardvark" should return a count of 3 for the "a"s, 2 for the "r"s, and 1 for everything else.

Putting integers in tabular form without whitespace in Python

Sorry that I ask this here, because this seems really elementary and is most likely asked before. However, I have been searching and trying for hours and I couldn't find anything that helped me out. I want to write a program that asks for an upper bound and returns a table with pairs of numbers (m,n) such that the sum of of divisors of n (excluding n) equals m, and vice versa.
Now I wrote the following
bound = int(input('upper bound = '))
l = len(str(bound))
for x in range(1,l):
print(' ', end='')
print('m', end=' ')
for y in range(1,l):
print(' ', end='')
print('n', end='')
for i in range(1,bound):
for j in range (1, bound):
if j == i:
break
som_i = 0
som_j = 0
for k in range(1,i):
if i % k == 0:
som_i += k
for l in range(1,j):
if j % l == 0:
som_j += l
if som_i == j and som_j == i:
print('{:{prec}d}'.format(j, prec = l).rstrip(''), end="")
print('{:{prec}d}'.format(i, prec = l+2).lstrip(''), end="")
The problem is that I want the pair to be displayed in tabular form side to side and with the right indentation, depending on the length of the number. Whatever I tried (I read so many treads with similar questions already) Python keeps adding a whitespace.
Can anyone help me out on this? I am really new to Python and I cannot figure this out myself. If relevant, I am using version 3.6.
EDIT:
For example, when I run the program I get:
upper bound = 300
m n
220
284
while I would like to get
upper bound = 300
m n
220 284
And similar for larger inputs.
EDIT2 My question is not a duplicate, since i already tried adding
end=""
which did not work.
The first problem is that you're not using end='' after printing the j value, but you apparently already know about that. You also are using it after printing the n header, which you don't want.
Your edited version fixes the missing end='' after the j print, but then adds one after the i print, which, again, you don't want.
I'm not sure you understand what end='' means, so you're just putting it into your code randomly. That isn't going to get you very far. You can read the docs for print, but the short version is: use end='' when you're printing something that isn't supposed to be the end of a line, like that m header and j value, but don't use it when you're printing something that is supposed to be the end of a line, like that n header and i value.
The second problem is that l is just way too big. After for l in range(1,j):, it's going to be the same value as j, which means it's going to be 219, so you're going to print that 220 filled out to 219 characters, and that 284 filled out to 221 characters. So, unless your terminal is more than 446 characters wide, it's going to scroll across multiple lines and look like a mess. I think what you may want here is to use 3 and 5.
Or, maybe, you have some other variable that's supposed to be 3, and you want to use (let's call that variable x) x and x+2 instead of l and l+2. But I don't see any obvious candidates in your code.
So:
# ... unchanged lines
print('n') # no end='' here
# ... more unchanged lines
# using 3 and 5 instead of l and l+2, and adding end=''
print(('{:{prec}d}'.format(j, prec = 3)).rstrip(''), end='')
print(('{:{prec}d}'.format(i, prec = 5)).lstrip(''))
And now, the output is:
upper bound = 300
m n
220 284

Why do I get a 'list index out of range' error for the below code using a for loop:

Problem Statement: Given a nested list nl consisting of a set of integers, write a python script to find the sum of alternate elements of the sub-lists.
nl = [[1,2,3],[4,5,6],[7,8,9],[10,11,12]]
sum = 0
n = 0
j=[]
for ele in nl:
for i in ele:
j.append(i)
for a in j:
sum = sum + j[n]
n = n + 2
print(sum)
When I run this code, I get an error:
Traceback (most recent call last):
File "C:\Users\ARUDRAVA\Contacts\Desktop\lists Assigment\assigment2.py",line 14, in <module>
sum = sum + j[n]
IndexError: list index out of range
Why is this error generated?
This is how it's usually done in Python:
nl = [[1,2,3],[4,5,6],[7,8,9],[10,11,12]]
total = sum(number for sublist in nl for number in sublist)
Don't name the variable sum - that would "hide" a built-in function. Exactly the function you need in fact.
Anyway, the error in your code was here:
sum = sum + j[n]
It should have been:
sum = sum + a
Your outer loops look like this:
for ele in nl:
for i in ele:
j.append(i)
# inner loop.
The first time the inner loop is reached, only one element has been appended to the list j. The second time the inner loop is reached, two elements have been appended to j, so the second time the loop is reached, j is [1,2].
It seems from your comment that you think that when the inner loop is reached, that j contains all 12 numbers from nl. That's not correct. Perhaps you meant for the "inner loop" to come after the two outside loops and not inside them.
Let's it is the second time that the inner loop is reached j=[1,2], and suppose n=0 (it might be larger than this but it can't be smaller)
Let's check the inner loop
for a in j:
sum = sum + j[n]
n = n + 2
Because j has two elements, it will loop twice:
The first time through the loop it adds j[0] to sum, and sets n=0+2
The second time through the loop it tries to add j[2] to sum, which is a IndexError.
You will need to rethink the logic of your program. Good Luck!

Categories

Resources