Here is the code:
a = "218916754"
b = ""
while len(a) > 1:
b = b + a[0]
a = a[2:] + a[1]
b = b + a
print b
The result is "281749561". My question is, how this happens? In this code, there is no i, no i+=1 etc, how the iteration happens? Is something special about the while loop? I mean the index function is hidden in this while loop?
This line:
a = a[2:] + a[1]
results in a string that is one character shorter than the previous. Once this string has a length of 1, the loop exits.
There is no "index function" or index "i" in a while clause. Instead, code such as:
while <expression>:
<body>
means, "repeat <body> as long as <expression> is True"
Initially when we are programming we are always using indexes (commonly - i,x,y,t) to keep track of iterations of loops. It is because we always have a loop that we want to run for a know fixed number of iterations. But indexes are not something fundamental to the loop. Loops are tools which are much more than that.
A loop consists of a condition and body. The body is executed as many times, depending on whether the condition is True or False. (Conditions are boolean conditions).
So in the given code the condition is len(a)>1. That is - if the length of string "a" is greater than 1. So the body of the loop will be executed as many times as long as this condition is true. (You can also see, if wrongly implemented you could have loops that do not terminate).
To see what exactly is happening in this particular program, You can use the print statement inside the loop and a dummy variable "iteration_num" which I am using to keep track of the iterations. Go ahead and run the following code and see for yourself.
a = "218916754"
b = ""
iteration_num = 1
while len(a) > 1:
b = b + a[0]
a = a[2:] + a[1]
print "iteration number: " + str(iteration_num)
print "a: " + a
print "b: " + b
iteration_num = iteration_num + 1
b = b + a
print b
Related
The aim of this program is to find all the integer pairs of three that are in range of 0 and 57 that can form a triangle. (I made the program for a Math problem)
import random
import time
dict = {}
current_list = []
key_num = 0
def main():
global key_num
a = random.randint(1, 57)
b = random.randint(1, 57)
c = random.randint(1, 57)
if a + b > c and a + c > b and b + c > a:
current_list.append(a)
current_list.append(b)
current_list.append(c)
current_list.sort()
for i in range(0, key_num):
if dict[i] == current_list:
main()
dict.setdefault(key_num, current_list)
key_num += 1
current_list.clear()
print(str(key_num))
print(dict)
time.sleep(0.8)
while True:
main()
However, when I run it, there are two problems.
First, after a while program is launched, an error RecursionError: maximum recursion is displayed. For this, I have tried to set the limit higher to 10^5 but the program just crashed after a while.
Second, the dictionary isn't inputting any new items during the process.
I am not that experienced in python and thanks a lot if you would like to help.
Also, a + b > c and a + c > b and b + c > a is the criteria for an triangle: the sum of any two sides is bigger than the third side.
Ok, so first of all, in general stack overflow questions should be condensed to the point that their answers can be useful to others.
Now, there are several problem with your code:
you call main inside main. When you say:
if dict[i] == current_list:
main()
what I think you mean is: if this set of integers has already been checked, go back to the beginning. But instead it runs the function main() again, this time inside of itself. What you should do instead is write:
if dict[i] == current_list:
return
You don't have an end condition. The code won't stop because there is no way for it to exit the loop. You need some way to determine when it is finished.
dict.setdefault(key_num, current_list) has several issues. Number one is that the way you assign an item to a dictionary is: dict[key_num] = current_list. setdefault is a totally different thing and, while it somtimes produces the same result, it isn't the thing you are looking for.
The next issue is that you clear current_list in the next line, which means the list that you just put into your dictionary is now an empty list.
My recommendation is to restructure the code into several for loops to check every combination:
identifiedSets = [];
for a in range(1, 57):
for b in range(1, 57):
for c in range(1, 57):
if a + b > c and a + c > b and b + c > a:
newList = [a, b, c]
newList.sort();
identifiedSets.append(str(newList))
print(str(identifiedSets))
This way you will iterate through every possible combination of numbers and, by storing the results as a list of strings, you can check if those strings have already been added to the list. Finally, printing the results is easy because the results are already strings.
The question for the code is 'input a word and check whether the first character of the word is repeated in the word again or not. If yes then change all the repeating characters to $ except the first character.'
So I coded the following and used the logic to start the loop from the second character of the word so that first character remains unchanged.
a=input()
for i in range(1,len(a)):
if(a[i]==a[0]):
b=a.replace(a[i],'$')
print(b)
for the above program I gave the input as 'agra' and to my surprise got the output as '$gr$'. the first character was also changed.
What is the problem with my logic? and what other solution do you suggest?
That is more simply done like:
Code:
b = a[0] + a[1:].replace(a[0], '$')
Test Code:
a = 'stops'
b = a[0] + a[1:].replace(a[0], '$')
print(b)
Results:
stop$
For the correct solution in python, see Stephen Rauch's answer.
I think that what you where trying to achieve, in a very "unpythonic" way, is:
a = input()
b = a # b is a copy
for i in range(1, len(a)):
if a[i] == a[0]:
# replace i-th char of b by '$''
print (b)
How to do that replacement? In python: strings are immutable, that means you cannot replace a char "in place". Try to do this:
a='agra'
a[3] = '$'
And you'll get an error:
TypeError: 'str' object does not support item assignment
If you want to replace the i-th char of a string by $, you have to write:
b = b[:i] + '$' + b[i+1:]
That is: build a new string from b[0], ..., b[i-1], add a $ and continue with b[i+1], ..., b[len(a)-1]. If you use this in your code, you get:
a = input()
b = a
for i in range(1, len(a)):
if a[i] == a[0]:
b = b[:i] + '$' + b[i+1:]
print (b)
Okay, it works but don't do that because it's very "unpythonic" and inefficient.
BEGIN EDIT
By the way, you don't need to replace, you can just build the string character by character:
a = input()
b = a[0] # start with first char
for i in range(1, len(a)):
if a[i] == a[0]:
b += '$' # $ if equals to first char
else:
b += a[i] # else the current char
print (b)
END EDIT
That gave me this idea:
a=input()
b="".join('$' if i!=0 and c==a[0] else c for i,c in enumerate(a))
print(b)
Explanation: the list comprehension takes all characters of a along with their position i (that's what enumerate does). For every couple position, character, if the position is not 0 (not the first character) and if the character is equal to a[0], then put a $. Else put the character itself. Glue everything together to make a new string.
Again, that's not the right way to do what you are trying to do, because there is another way that is neater and easier (see Stephen Rauch's answer), but is shows how you can sometimes handle difficulties in python.
a=input()
for i in range(1,len(a)):
if(a[i]==a[0]):
b=a[1:len(a)].replace(a[i],'$')
print(a[0]+b)
you changed whole word/sentence 'a': a.replace(...)
This is the problem definition:
Given a string of lowercase letters, determine the index of the
character whose removal will make a palindrome. If is already a
palindrome or no such character exists, then print -1. There will always
be a valid solution, and any correct answer is acceptable. For
example, if "bcbc", we can either remove 'b' at index or 'c' at index.
I tried this code:
# !/bin/python
import sys
def palindromeIndex(s):
# Complete this function
length = len(s)
index = 0
while index != length:
string = list(s)
del string[index]
if string == list(reversed(string)):
return index
index += 1
return -1
q = int(raw_input().strip())
for a0 in xrange(q):
s = raw_input().strip()
result = palindromeIndex(s)
print(result)
This code works for the smaller values. But taken hell lot of time for the larger inputs.
Here is the sample: Link to sample
the above one is the bigger sample which is to be decoded. But at the solution must run for the following input:
Input (stdin)
3
aaab
baa
aaa
Expected Output
3
0
-1
How to optimize the solution?
Here is a code that is optimized for the very task
def palindrome_index(s):
# Complete this function
rev = s[::-1]
if rev == s:
return -1
for i, (a, b) in enumerate(zip(s, rev)):
if a != b:
candidate = s[:i] + s[i + 1:]
if candidate == candidate[::-1]:
return i
else:
return len(s) - i - 1
First we calculate the reverse of the string. If rev equals the original, it was a palindrome to begin with. Then we iterate the characters at the both ends, keeping tab on the index as well:
for i, (a, b) in enumerate(zip(s, rev)):
a will hold the current character from the beginning of the string and b from the end. i will hold the index from the beginning of the string. If at any point a != b then it means that either a or b must be removed. Since there is always a solution, and it is always one character, we test if the removal of a results in a palindrome. If it does, we return the index of a, which is i. If it doesn't, then by necessity, the removal of b must result in a palindrome, therefore we return its index, counting from the end.
There is no need to convert the string to a list, as you can compare strings. This will remove a computation that is called a lot thus speeding up the process. To reverse a string, all you need to do is used slicing:
>>> s = "abcdef"
>>> s[::-1]
'fedcba'
So using this, you can re-write your function to:
def palindromeIndex(s):
if s == s[::-1]:
return -1
for i in range(len(s)):
c = s[:i] + s[i+1:]
if c == c[::-1]:
return i
return -1
and the tests from your question:
>>> palindromeIndex("aaab")
3
>>> palindromeIndex("baa")
0
>>> palindromeIndex("aaa")
-1
and for the first one in the link that you gave, the result was:
16722
which computed in about 900ms compared to your original function which took 17000ms but still gave the same result. So it is clear that this function is a drastic improvement. :)
def unZip(master3):
c = len(master3)
sub1=''
sub2=''
for i in range(0,c,2):
sub1+=master3[i]
sub2+=master3[i+1]
print(sub1,",",sub2)
basically I have written this code that separates alternative char from string and shows them separately,
I have been trying to convert or comprehend this with recursion but I have been failing lately.
Here is my try, can someone tell me how should I approach it?
def unzip(a):
storage1=''
storage2=''
storage3=''
storage4=''
if len(a)==0:
return 0
else:
if len(a)>=1:
storage1=a[0::2]
storage2=a[1::2]
storage3+=storage1
storage4+=storage2
print(storage3,storage4)
return unzip(a[0]+a[1:])
instead of using slicing to determine your strings you should be taking one character at a time off your string and then recalling your recursive function like so
def unzip(s, a, b='', c=''):
if len(a) == 0:
return b + ', ' + c
if s%2 == 0:
b += a[0]
else:
c += a[0]
return unzip(s+1, a[1:], b, c)
print unzip(0, 'HelloWorld')
Hlool, elWrd
What that does is it starts with the string a and alternates between adding to b or c with the variable s depending on whether it is even or odd. Add the first letter of a to either b or c and then remove that letter from a. Then call the function again but with s+1. If the length of a is zero then return b and c and then print your result
To get the same results with what you have you could simplify yours down to
a = 'HelloWorld'
storage1=a[0::2]
storage2=a[1::2]
print(storage1,storage2)
('Hlool', 'elWrd')
The slicing takes care of getting every other letter in a and then you can just print that. The way you have it set up now it will just keep passing a and become an infinite loop since the size of a will never change.
I am a beginner in Python currently working through Project Euler's problems (here for those who have not heard about it). I have solved this particular problem, however it leaves me with some questions:
def fibsum():
result = []
a, b = 0, 1
while True:
a, b = b, a + b
print b
if b < 4000000 and b % 2 == 0:
result.append(b)
if b > 4000000:
break
print sum(result)
fibsum()
When I run this using PowerShell, first it prints out all the numbers I need (although, it goes one over), and then finally prints the sum:
1
2
3
5
8
...
3524578
5702887 <-- This is over 4,000,000. Why is this here?
4613732 <-- This is the answer.
Is there any way that I can have the loop stop iterating before it reaches the first value over 4,000,000?
For the sake of saving space, is there any way that I can have all of the values print out in a list format ([ , , , ]), if I decide to use print?
When I replace print in the original code with yield or return(for the variable b), the program won't print anything out, despite there still being
print sum(result)
at the end of the function.
Is there any way that I can make this easier, without having to define result and appending values to it? When the values are returned in a format similar to the actual outcome, sum() doesn't seem to work.
1.Just move the 2nd condition before you print b:
while True:
a, b = b, a + b
if b > 4000000:
break
print b
if b < 4000000 and b % 2 == 0:
result.append(b)
2.Don't print b in loop, rather print the result once you break out.
3.Well, as for return, it's pretty clear that you return out of function, so the following code in function is not executed and hence your list is not populated.
yield is used to create a generator function, where every execution of your function returns the next value. So, you would have to call your function multiple times, thus adding the yielded value to a list defined outside. And when there is nothing to return, your function will break.
To understand yield keyword usage more clearly, take a look at this post: What does the "yield" keyword do in Python?
You can edit your code to use yield like this (haven't tested it):
def fibsum():
a, b = 0, 1
while True:
a, b = b, a + b
if b > 4000000:
break
yield b
result = []
for val in fibsum():
if val < 4000000 and val % 2 == 0:
result.append(val)
print sum(result)
So, in for loop, each call to fibsum() function generates the next value, which you add in the list, based on the condition.