What I have so far:
def balance_equation(species,coeff):
data=zip(coeff,species)
positive=[]
negative=[]
for (mul,el) in data:
if int(mul)<0:
negative.append((el,mul))
if int(mul)>0:
positive.append((el,mul))
I know this does not print anything. What I have is a function that takes in two lists species=['H2O','O2','CO2'] and coeff=['1','3','-4']. I need it to print like so:
1H20+3O2=4CO2
I started by putting the negative coeff and species in one list and the positive in the other. I just can seem to be able to get the two to print right.
Try this:
species = ["H2O", "CO2", "O2"]
coeff = ['1', '-4', '3']
pos = [c + s for c, s in zip(coeff, species) if int(c) > 0]
neg = [c[1:] + s for c, s in zip(coeff, species) if int(c) < 0]
print ("+".join(pos))+"="+("+".join(neg))
EDIT: I took out the spaces.
2nd EDIT: coeff is a list of strings.
You should also test if pos or neg are empty to replace them with 0s when appropriate. It appears that the coefficients are integers.
Breaking things down into steps is a good way to solve things (you can always recombine the steps later), and you've got 80% of the way there.
You already have positive and negative lists. So, you need to convert each one into a string, then just:
print poshalf, "=", neghalf
So, how do you convert positive into poshalf? Well, it's a representation of each member, separated by '+', so if you had a function stringify that could turn each member into its representation, it's just:
poshalf = '+'.join(stringify(el, mul) for (el, mul) in pos)
neghalf = '+'.join(stringify(el, mul)[1:] for (el, mul) in neg)
The [1:] there is to take out the - sign. If mul is actually an integer rather than a string, it probably makes sense to just negate the value before passing it to stringify:
neghalf = '+'.join(stringify(el, -mul) for (el, mul) in neg)
Now, what does that "stringify" function look like? Well, each one member is an (el, mul) pair. If they were both strings, you could just add them. From your previous questions, mul may end up being some kind of number at this point, but that's almost as easy:
def stringify(el, mul):
return str(mul) + el
Put it all together, and you're done.
One way to make this all simpler: If you never use the (el, mul) for any other purpose except to call stringify on it, just call stringify in the first place and store the result:
def balance_equation(species,coeff):
data=zip(coeff,species)
positive=[]
negative=[]
for (mul,el) in data:
if int(mul)<0:
negative.append(str(mul)[1:] + el)
if int(mul)>0:
positive.append(str(mul) + el)
return positive, negative
Remember that last line, which you've left off both versions of your previous question and this question! If you never return the values, all that effort figuring them out is wasted, and the caller just gets None as an answer.
Obviously either the str or the int is unnecessary, but I've left them both in for safety; you should look at your surrounding code and remove the unnecessary one. (If you're taking mul as an int, you probably want str(-mul) instead of str(mul)[1:], as described earlier.)
Once you've got this, if you understand list comprehensions, you might realize that this is a familiar pattern: start with [], loop over some other collection, and append each value that meets some test. In other words:
def balance_equation(species,coeff):
data=zip(coeff,species)
positive = [str(mul) + el for (mul, el) in data if int(mul) > 0]
negative = [str(mul) + el for (mul, el) in data if int(mul) < 0]
return positive, negative
You might notice that you can simplify this even further—the only thing you use the lists for is to build the strings, so maybe you just want a function that returns a string equation (in which case you can use a generator expression instead of a list comprehension—if you don't know about them yet, ignore that part).
def balance_equation(species,coeff):
data=zip(coeff,species)
positive = '+'.join(str(mul) + el for (mul, el) in data if int(mul) > 0)
negative = '-'.join(str(mul) + el for (mul, el) in data if int(mul) < 0)
return positive + '=' + negative
Of course now you're returning a string instead of a pair of lists, so you have to change your calling code to just print balance_equation(species, coeff) instead of combining the lists.
One last thing: You seem to reverse the order of the coefficients/multipliers and species/elements at each call. For example:
def balance_equation(species,coeff):
data=zip(coeff,species)
Unless there's a good reason to do otherwise, it's better to pick one order and be consistent throughout, or you're invariably going to run into a bug where you get them backwards.
Related
Came across a pretty neat solution on adding binary numbers
class Solution:
def addBinary(self, a: str, b: str) -> str:
carry = 0
result = ''
a = list(a)
b = list(b)
while a or b or carry:
if a:
carry += int(a.pop())
if b:
carry += int(b.pop())
result += str(carry %2)
carry //= 2
return result[::-1]
For me it is intuitive to read numbers from the right to left, in which case the 1 that is carried over(1+1=10) will be from right to left as well. So why is it that reading it left to right and reversing it is the same, even when say length of strings a and b are different?
[EDIT] misunderstand and assumed why he did result[::-1] Thanks for the replies!
Your algorithm is not reading the strings left to right. It is reading them right to left.
You are reading the digits with list.pop(). See the documentation: https://docs.python.org/3/tutorial/datastructures.html
list.pop([i]) Remove the item at the given position in the list, and return it. If
no index is specified, a.pop() removes and returns the last item in
the list. (The square brackets around the i in the method signature denote that the parameter is optional, not that you should type square brackets at that position. You will see this notation frequently in the Python Library Reference.)
However, the resulting digits are added right to left to the string result, because of result += str(carry %2). This is why result needs to be reversed at the end.
If you replace result += str(carry %2) with result = str(carry %2) + result and return result[::-1] with return result, you will see that the result is in the correct order.
Sure, the code could have collected the digits from "left to right", like this:
result = str(carry %2) + result
... and then omit the reversal at the end. It would not make a difference for the output. Possibly the author considered that doing it with += would give a performance gain, even when taking the reversal operation into account. In my tests I can confirm this performance gain.
Note that either way, the input values are read from right to left, as the digits are taken from both lists with pop(). It is only the placement of the resulting digits which is reversed.
Here is the problem I'm trying to solve:
Given an int, ops, n, create a function(int, ops, n) and slot operators between digits of int to create equations that evaluates to n. Return a list of all possible answers. Importing functions is not allowed.
For example,
function(111111, '+-%*', 11) => [1*1+11/1-1 = 11, 1*1/1-1+11 =11, ...]
The question recommended using interleave(str1, str2) where interleave('abcdef', 'ab') = 'aabbcdef' and product(str1, n) where product('ab', 3) = ['aaa','aab','abb','bbb','aba','baa','bba'].
I have written interleave(str1, str2) which is
def interleave(str1,str2):
lsta,lstb,result= list(str1),list(str2),''
while lsta and lstb:
result += lsta.pop(0)
result += lstb.pop(0)
if lsta:
for i in lsta:
result+= i
else:
for i in lstb:
result+=i
return result
However, I have no idea how to code the product function. I assume it has to do something with recursion, so I'm trying to add 'a' and 'b' for every product.
def product(str1,n):
if n ==1:
return []
else:
return [product(str1,n-1)]+[str1[0]]
Please help me to understand how to solve this question. (Not only the product it self)
General solution
Assuming your implementation of interleave is correct, you can use it together with product (see my suggested implementation below) to solve the problem with something like:
def f(i, ops, n):
int_str = str(i)
retval = []
for seq_len in range(1, len(int_str)):
for op_seq in r_prod(ops, seq_len):
eq = interleave(int_str, op_seq)
if eval(eq) == n:
retval.append(eq)
return retval
The idea is that you interleave the digits of your string with your operators in a varying order. Basically I do that with all possible sequences of length seq_len which varies from 1 to max, which will be the number of digits - 1 (see assumptions below!). Then you use the built-in function eval to evaluate the expression returned by inteleave for a specific sequence of the operators and compare the result with the desired number, n. If the expression evaluates to n you append it to the return array retval (initially empty). After you evaluated all the expressions for all possible operator sequences (see assumptions!) you return the array.
Assumptions
It's not clear whether you can use the same operator multiple times or if you're allowed to omit using some. I assumed you can use the same operator many times and that you're allowed to omit using an operator. Hence, the r_prod was used (as suggested by your question). In case of such restrictions, you will want to use permutations (of possibly varying length) of the group of operators.
Secondly, I assumed that your implementation of the interleave function is correct. It is not clear if, for example, interleave("112", "*") should return both "1*12" and "11*2" or just "1*12" like your implementation does. In the case both should be returned, then you should also iterate over the possible ways the same ordered sequence of operators can be interleaved with the provided digits. I omitted that, because I saw that your function always returns a single string.
Product implementation
If you look at the itertools docs you can see the equivalent code for the function itertools.product. Using that you'd have:
def product(*args, repeat=1):
pools = [tuple(pool) for pool in args] * repeat
result = [[]]
for pool in pools:
result = [x+[y] for x in result for y in pool]
for prod in result:
yield tuple(prod)
a = ["".join(x) for x in product('ab', repeat=3)]
print(a)
Which prints ['aaa', 'aab', 'aba', 'abb', 'baa', 'bab', 'bba', 'bbb'] -- what I guess is what you're after.
A more specific (assuming iterable is a string), less efficient, but hopefully more understandable solution would be:
def prod(string, r):
if r < 1:
return None
retval = list(string)
for i in range(r - 1):
temp = []
for l in retval:
for c in string:
temp.append(l + c)
retval = temp
return retval
The idea is simple. The second parameter r gives you the length of the strings you want to produce. The characters in the string give you the elements from which you build the string. Hence, you first generate a string of length 1 that starts with each possible character. Then for each of those strings you generate new strings by concatenating the old string with all of the possible characters.
For example, given a pool of characters "abc", you'll first generate strings "a", "b", and "c". Then you'll replace string "a" with strings "aa", "ab", and "ac". Similarly for "b" and "c". You repeat this process n-times to get all possible strings of length r generated by drawing with replacement from the pool "abc".
I'd think it would be a good idea for you to try to implement the prod function recursively. You can see my ugly solution below, but I'd suggest you stop reading this now and try to do it without looking at my suggestion first.
SPOILER BELOW
def r_prod(string, r):
if r == 1:
return list(string)
else:
return [c + s for c in string for s in r_prod(string, r - 1)]
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'd like to compute the edits required to transform one string, A, into another string B using only inserts and deletions, with the minimum number of operations required.
So something like "kitten" -> "sitting" would yield a list of operations something like ("delete at 0", "insert 's' at 0", "delete at 4", "insert 'i' at 3", "insert 'g' at 6")
Is there an algorithm to do this, note that I don't want the edit distance, I want the actual edits.
I had an assignment similar to this at one point. Try using an A* variant. Construct a graph of possible 'neighbors' for a given word and search outward using A* with the distance heuristic being the number of letter needed to change in the current word to reach the target. It should be clear as to why this is a good heuristic-it's always going to underestimate accurately. You could think of a neighbor as a word that can be reached from the current word only using one operation. It should be clear that this algorithm will correctly solve your problem optimally with slight modification.
I tried to make something that works, at least for your precise case.
word_before = "kitten"
word_after = "sitting"
# If the strings aren't the same length, we stuff the smallest one with spaces
if len(word_before) > len(word_after):
word_after += " "*(len(word_before)-len(word_after))
elif len(word_before) < len(word_after):
word_before += " "*(len(word_after)-len(word_before))
operations = []
for idx, char in enumerate(word_before):
if char != word_after[idx]:
if char != " ":
operations += ["delete at "+str(idx)]
operations += ["insert '"+word_after[idx]+"' at "+str(idx)]
print(operations)
This should be what you're looking for, using itertools.zip_longest to zip the lists together and iterate over them in pairs compares them and applies the correct operation, it appends the operation to a list at the end of each operation, it compares the lists if they match and breaks out or continues if they don't
from itertools import zip_longest
a = "kitten"
b = "sitting"
def transform(a, b):
ops = []
for i, j in zip_longest(a, b, fillvalue=''):
if i == j:
pass
else:
index = a.index(i)
print(a, b)
ops.append('delete {} '.format(i)) if i != '' else ''
a = a.replace(i, '')
if a == b:
break
ops[-1] += 'insert {} at {},'.format(j, index if i not in b else b.index(j))
return ops
result = transform(a, b)
print(result, ' {} operation(s) was carried out'.format(len(result)))
Since you only have delete and insert operations, this is an instance of the Longest Common Subsequence Problem : https://en.wikipedia.org/wiki/Longest_common_subsequence_problem
Indeed, there is a common subsequence of length k in two strings S and T, S of length n and T of length m, if and only only you can transform S into T with m+n-2k insert and delete operations. Think about this as intuition : the order of the letters is preserved both when adding and deleting letters, as well as when taking a subsequence.
EDIT : since you asked for the list of edits, a possible way to do the edits is to first remove all the characters of S not in the common subsequence, and then insert all the characters of T that are not the in common subsequence.
I have a list of numbers that represent the number of 1s in a row and I have an integer that represents the length of the entire sequence. So for example, if I get list [1, 2, 3] and length 8, then the only possible bit sequence is 10110111. But if the length was 9, I should get
010110111, 100110111, 101100111 and 101101110. I wonder if there is a simply pythonic way of doing this. My current method is
def genSeq(seq, length):
strSeq = [str(i) for i in seq]
strRep = strSeq + ["x" for i in xrange(length-sum(seq))]
perm = list(set(permutations(strRep)))
legalSeq = [seq for seq in perm if isLegal(seq) and [char for char in seq if char.isdigit()] == strSeq]
return [''.join(["1"*int(i) if i.isdigit() else "0" for i in seq]) for seq in legalSeq]
def isLegal(seq):
for i in xrange(len(seq)-1):
if seq[i].isdigit() and seq[i+1].isdigit(): return False
return True
print genSeq([1, 2, 3], 9)
My approach is as follows:
Figure out how many zeros will appear in the result sequences, by doing the appropriate arithmetic. We'll call this value n, and call the length of the input list k.
Now, imagine that we write out the n zeros for a given result sequence in a row. To create a valid sequence, we need to choose k places where we'll insert the appropriate number of ones, and we have n + 1 choices of where to do so - in between any two digits, or at the beginning or end. So we can use itertools.combinations to give us all the possible position-groups, asking it to choose k values from 0 up to n, inclusive.
Given a combination of ones-positions, in ascending order, we can figure out how many zeroes appear before the first group of ones (it's the first value from the combination), the second (it's the difference between the first two values from the combination), etc. As we iterate, we need to alternate between groups of zeros (the first and/or last of these might be empty) and groups of ones; so there is one more group of zeros than of ones, in general - but we can clean that up by adding a "dummy" zero-length group of ones to the end. We also need to get "overlapping" differences from the ones-positions; fortunately there's a trick for this.
This part is tricky when put all together; I'll write a helper function for it, first:
def make_sequence(one_positions, zero_count, one_group_sizes):
zero_group_sizes = [
end - begin
for begin, end in zip((0,) + one_positions, one_positions + (zero_count,))
]
return ''.join(
'0' * z + '1' * o
for z, o in zip(zero_group_sizes, one_group_sizes + [0])
)
Now we can get back to the iteration over all possible sequences:
def generate_sequences(one_group_sizes, length):
zero_count = length - sum(one_group_sizes)
for one_positions in itertools.combinations(
range(zero_count + 1), len(one_group_sizes)
):
yield make_sequence(one_positions, zero_count, one_group_sizes)
Which we could of course then fold back into a single function, but maybe you'll agree with me that it's better to keep something this clever in more manageable pieces :)
This is more fragile than I'd like - the one_positions and one_group_sizes sequences need to be "padded" to make things work, which in turn requires assuming their type. one_positions will be a tuple because that's what itertools.combinations produces, but I've hard-coded the assumption that the user-supplied one_group_sizes will be a list. There are ways around that but I'm a little exhausted at the moment :)
Anyway, the test:
>>> list(generate_sequences([1,2,3], 9))
['101101110', '101100111', '100110111', '010110111']
>>> list(generate_sequences([1,1,1], 9))
['101010000', '101001000', '101000100', '101000010', '101000001', '100101000', '
100100100', '100100010', '100100001', '100010100', '100010010', '100010001', '10
0001010', '100001001', '100000101', '010101000', '010100100', '010100010', '0101
00001', '010010100', '010010010', '010010001', '010001010', '010001001', '010000
101', '001010100', '001010010', '001010001', '001001010', '001001001', '00100010
1', '000101010', '000101001', '000100101', '000010101']