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.
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.
here is my code:
def string_match(a, b):
count = 0
if len(a) < 2 or len(b) < 2:
return 0
for i in range(len(a)):
if a[i:i+2] == b[i:i+2]:
count = count + 1
return count
And here are the results:
Correct me if I am wrong but, I see that it didn't work probably because the two string lengths are the same. If I were to change the for loop statement to:
for i in range(len(a)-1):
then it would work for all cases provided. But can someone explain to me why adding the -1 makes it work? Perhaps I'm comprehending how the for loop works in this case. And can someone tell me a more optimal way to write this because this is probably really bad code. Thank you!
But can someone explain to me why adding the -1 makes it work?
Observe:
test = 'food'
i = len(test) - 1
test[i:i+2] # produces 'd'
Using len(a) as your bound means that len(a) - 1 will be used as an i value, and therefore a slice is taken at the end of a that would extend past the end. In Python, such slices succeed, but produce fewer characters.
String slicing can return strings that are shorter than requested. In your first failing example that checks "abc" against "abc", in the third iteration of the for loop, both a[i:i+2] and b[i:i+2] are equal to "c", and therefore count is incremented.
Using range(len(a)-1) ensures that your loop stops before it gets to a slice that would be just one letter long.
Since the strings may be of different lengths, you want to iterate only up to the end of the shortest one. In addition, you're accessing i+2, so you only want i to iterate up to the index before the last item (otherwise you might get a false positive at the end of the string by going off the end and getting a single-character string).
def string_match(a: str, b: str) -> int:
return len([
a[i:i+2]
for i in range(min(len(a), len(b)) - 1)
if a[i:i+2] == b[i:i+2]
])
(You could also do this counting with a sum, but this makes it easy to get the actual matches as well!)
You can use this :
def string_match(a, b):
if len(a) < 2 or len(b) < 0:
return 0
subs = [a[i:i+2] for i in range(len(a)-1)]
occurence = list(map(lambda x: x in b, subs))
return occurence.count(True)
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. :)
A string is palindrome if it reads the same forward and backward. Given a string that contains only lower case English alphabets, you are required to create a new palindrome string from the given string following the rules gives below:
1. You can reduce (but not increase) any character in a string by one; for example you can reduce the character h to g but not from g to h
2. In order to achieve your goal, if you have to then you can reduce a character of a string repeatedly until it becomes the letter a; but once it becomes a, you cannot reduce it any further.
Each reduction operation is counted as one. So you need to count as well how many reductions you make. Write a Python program that reads a string from a user input (using raw_input statement), creates a palindrome string from the given string with the minimum possible number of operations and then prints the palindrome string created and the number of operations needed to create the new palindrome string.
I tried to convert the string to a list first, then modify the list so that should any string be given, if its not a palindrome, it automatically edits it to a palindrome and then prints the result.after modifying the list, convert it back to a string.
c=raw_input("enter a string ")
x=list(c)
y = ""
i = 0
j = len(x)-1
a = 0
while i < j:
if x[i] < x[j]:
a += ord(x[j]) - ord(x[i])
x[j] = x[i]
print x
else:
a += ord(x[i]) - ord(x[j])
x [i] = x[j]
print x
i = i + 1
j = (len(x)-1)-1
print "The number of operations is ",a print "The palindrome created is",( ''.join(x) )
Am i approaching it the right way or is there something I'm not adding up?
Since only reduction is allowed, it is clear that the number of reductions for each pair will be the difference between them. For example, consider the string 'abcd'.
Here the pairs to check are (a,d) and (b,c).
Now difference between 'a' and 'd' is 3, which is obtained by (ord('d')-ord('a')).
I am using absolute value to avoid checking which alphabet has higher ASCII value.
I hope this approach will help.
s=input()
l=len(s)
count=0
m=0
n=l-1
while m<n:
count+=abs(ord(s[m])-ord(s[n]))
m+=1
n-=1
print(count)
This is a common "homework" or competition question. The basic concept here is that you have to find a way to get to minimum values with as few reduction operations as possible. The trick here is to utilize string manipulation to keep that number low. For this particular problem, there are two very simple things to remember: 1) you have to split the string, and 2) you have to apply a bit of symmetry.
First, split the string in half. The following function should do it.
def split_string_to_halves(string):
half, rem = divmod(len(string), 2)
a, b, c = '', '', ''
a, b = string[:half], string[half:]
if rem > 0:
b, c = string[half + 1:], string[rem + 1]
return (a, b, c)
The above should recreate the string if you do a + c + b. Next is you have to convert a and b to lists and map the ord function on each half. Leave the remainder alone, if any.
def convert_to_ord_list(string):
return map(ord, list(string))
Since you just have to do a one-way operation (only reduction, no need for addition), you can assume that for each pair of elements in the two converted lists, the higher value less the lower value is the number of operations needed. Easier shown than said:
def convert_to_palindrome(string):
halfone, halftwo, rem = split_string_to_halves(string)
if halfone == halftwo[::-1]:
return halfone + halftwo + rem, 0
halftwo = halftwo[::-1]
zipped = zip(convert_to_ord_list(halfone), convert_to_ord_list(halftwo))
counter = sum([max(x) - min(x) for x in zipped])
floors = [min(x) for x in zipped]
res = "".join(map(chr, floors))
res += rem + res[::-1]
return res, counter
Finally, some tests:
target = 'ideal'
print convert_to_palindrome(target) # ('iaeai', 6)
target = 'euler'
print convert_to_palindrome(target) # ('eelee', 29)
target = 'ohmygodthisisinsane'
print convert_to_palindrome(target) # ('ehasgidihmhidigsahe', 84)
I'm not sure if this is optimized nor if I covered all bases. But I think this pretty much covers the general concept of the approach needed. Compared to your code, this is clearer and actually works (yours does not). Good luck and let us know how this works for you.
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.