More pythonic/elegant way to do this Python string slicing? - python

So I have a function that takes two string inputs - it slices them so that if of even length, the length of the front segment is the same as that of the back, and if of odd length, the middle character goes to the front segment (i.e. hello -> hel , lo). And then you mix and match the resulting front and back segments of the two string to produce the final output.
I want to be able to do this all under one function and what I came up with is ugly as all heck:
def front_back(a, b):
if len(a) % 2 == 0:
front_a = a[:len(a)/2]
back_a = a[len(a)/2:]
elif len(a) % 2 != 0:
front_a = a[:(len(a)/2)+1]
back_a = a[(len(a)/2)+1:]
if len(b) % 2 == 0:
front_b = b[:len(b)/2]
back_b = b[len(b)/2:]
elif len(b) % 2 != 0:
front_b = b[:(len(b)/2)+1]
back_b = b[(len(b)/2)+1:]
print front_a + front_b + back_a + back_b
front_back('Kitten', 'Donut') ---> KitDontenut
Is there a more pythonic/elegant way?
I couldn't figure out how to use lambdas (they can't process the if statement necessary to deal with even and odd length cases... i think?) if that's the way to go...
UPDATE:
thanks for the great suggestions everyone. just one more question:
when i try a version with lamdbas, based off a suggestion (for practice), I get a NameError that global name 's' isn't defined. What's wrong with how I wrote the lambda?
def front_back(a, b):
divideString = lambda s: s[:((1+len(s))//2)], s[((1+len(s))//2):]
a1, a2 = divideString(a)
b1, b2 = divideString(b)
print a1 + b1 + a2 + b2
front_back("hello","cookies")

You are making it more complicated than it needs to be:
def front_back(a, b):
mid_a, mid_b = (len(a) + 1) // 2, (len(b) + 1) // 2
front_a, back_a = a[:mid_a], a[mid_a:]
front_b, back_b = b[:mid_b], b[mid_b:]
print front_a + front_b + back_a + back_b
By adding 1 before dividing by 2 (floor division), you round up.
Demo:
>>> def front_back(a, b):
... mid_a, mid_b = (len(a) + 1) // 2, (len(b) + 1) // 2
... front_a, back_a = a[:mid_a], a[mid_a:]
... front_b, back_b = b[:mid_b], b[mid_b:]
... print front_a + front_b + back_a + back_b
...
>>> front_back('Kitten', 'Donut')
KitDontenut
You could inline the slicing even:
def front_back(a, b):
mid_a, mid_b = (len(a) + 1) // 2, (len(b) + 1) // 2
print a[:mid_a] + b[:mid_b] + a[mid_a:] + b[mid_b:]

def divideString(myString):
sliceHere = ( (1 + len(myString)) // 2)
return myString[:sliceHere], myString[sliceHere:]
def front_back(a, b):
a1, a2 = divideString(a)
b1, b2 = divideString(b)
return a1 + b1 + a2 + b2

def front_back(a, b):
return "".join([a[:(len(a)+1)/2]], b[:(len(b)+1)/2], \
a[(len(a)+1)/2]:], b[:(len(b)+1)/2]])

You could also add the result of length % 2 to the fronts:
def front_back(a, b):
ln_a, ln_b = len(a), len(b)
a1 = a2 = ln_a // 2
b1 = b2 = ln_b // 2
a1 += ln_a % 2
b1 += ln_b % 2
return a[:a1] + b[:b1] + a[-a2:] + b[-b2:]
print(front_back('Kitten', 'Donut'))

There are a some good answers here already, but for the sake of diversity, since you seem to be interested in multiple possibilities, here's a different way of looking at it:
import itertools
def front_back(a,b):
words = [a,b]
output = [[],[]]
for word in words:
if len(word) % 2 == 0:
output[0].append(word[:len(word)//2])
output[1].append(word[len(word)//2:])
else:
output[0].append(word[:len(word)//2+1])
output[1].append(word[(len(word)//2)+1:])
return "".join(output[0]) + "".join(output[1])
print(front_back('Kitten', 'Donut'))
Interpret with Python 3.

Related

Improving the runinng time of a numerical algorithm by parallel computation, using gmpy2 module of Python

I'm working on a numerical algorithm as follows.
import timeit
import gmpy2
import math
A = gmpy2.mpz(1000007777)
# Input a positive integer to factor.
# Put it inside the parentheses as "A = gmpy2.mpz(....)"
def factor(A):
B = gmpy2.mpz(math.sqrt(2 * A + 0.25) - 1)
D = gmpy2.mpz(A - (B * B + B) / 2)
while (D > 0):
B += 1
D = gmpy2.mpz(A - (B * B + B) / 2)
n = gmpy2.mpz(0)
while (D != 0 and B <= A):
if (D > 0):
B += 1
D -= B
else:
n += 1
D += n
if B > A:
return output(0, 0, 0)
else:
print(f"[B={B}, n={n}]")
if (B - n) % 2 == 0:
E = gmpy2.mpz((B - n) / 2)
F = gmpy2.mpz(B + n + 1)
else:
E = gmpy2.mpz(B - n)
F = gmpy2.mpz((B + n + 1) / 2)
return output(A, E, F)
def output(A, E, F):
if A == 0:
print(f"Initial Value Error: Reset the B value")
else:
if A % E != 0 or A % F != 0 or A != E * F:
print(f"[Error Occurred] {A} != {E} * {F}")
else:
print(f"{A} = {E} * {F}")
return 0
if __name__ == '__main__':
if A >= 2:
timer_start = timeit.default_timer()
factor(A)
timer_stop = timeit.default_timer()
running_time = round(timer_stop - timer_start, 6)
print("running time: ", running_time, " seconds")
else:
print("undefined for A<2")
(Note that the output of B and n comes out as [B=21739322, n=21739276] with our argument in the example code)
The task of this code aims to reach 0 by adding and subtracting integers. The D value shall oscillate between 0 until it reaches 0. I wanted to improve the running time of this task by parallel computation, using multiprocessing module of Python.
import timeit
import gmpy2
import math
import multiprocessing
A = gmpy2.mpz(1000007777)
# Input a positive integer to factor.
# Put it inside the parentheses as "A = gmpy2.mpz(....)"
k = 4
# Input the number of cores to be used as "k=..."
# [!!Caveat!!] Don't use too much number of cores which exceeds the
# availability of CPU resources of your personal computer environment.
# It can damage the CPU !!!
def factor(n):
if A < 2:
print("undefined for A<2")
else:
B = gmpy2.mpz(math.sqrt(2 * A + 0.25) - 1)
D = gmpy2.mpz(A - (B * B + B) / 2)
while (D > 0):
B += 1
D = gmpy2.mpz(A - (B * B + B) / 2)
D += gmpy2.mpz(n * (n + 1) / 2)
while (D != 0 and B <= A):
if (D > 0):
B += 1
D -= B
else:
D += k * n + (k * (k + 1)) / 2
n += k
if B > A:
return output(0, 0, 0)
else:
if (B - n) % 2 == 0:
E = gmpy2.mpz((B - n) / 2)
F = gmpy2.mpz(B + n + 1)
else:
E = gmpy2.mpz(B - n)
F = gmpy2.mpz((B + n + 1) / 2)
return output(A, E, F)
def output(A, E, F):
timer_stop = timeit.default_timer()
running_time = round(timer_stop - timer_start, 6)
if A == 0:
print(f"Initial Value Error: Reset the B or k value \n")
else:
if A % E != 0 or A % F != 0 or A != E * F:
print(f"[Error Occurred] {A} != {E} * {F} \n")
else:
print(f"[running time: {running_time} seconds] {A} = {E} * {F} \n")
return 0
if __name__ == '__main__':
n = []
timer_start = timeit.default_timer()
with multiprocessing.Pool(processes=k) as pool:
for x in range(0, k):
y = gmpy2.mpz(x)
n.append(y)
results = pool.map(factor, n)
The idea behind this is that, executing some addition of integers until meeting its target value, which is 0 in our code, shall be done faster if the added size of integers becomes bigger. For example, it is quite obvious that adding integers as 4+4+4... is faster to reach 100 than adding integers as 1+1+1...
However, my numerical experiments have shown that the latter code of multiprocessing module is nowhere faster than the previous code of single-core.
But, noticing that the value n=21739276 of which we mentioned above is divisible by 4, I've tried the modification of single-core version code as follows
import timeit
import gmpy2
import math
A = gmpy2.mpz(1000007777)
# Input a positive integer to factor.
# Put it inside the parentheses as "A = gmpy2.mpz(....)"
def factor(A):
B = gmpy2.mpz(math.sqrt(2 * A + 0.25) - 1)
D = gmpy2.mpz(A - (B * B + B) / 2)
while (D > 0):
B += 1
D = gmpy2.mpz(A - (B * B + B) / 2)
n = gmpy2.mpz(0)
while (D != 0 and B <= A):
if (D > 0):
B += 1
D -= B
else:
D += 4*n+10
n += 4
if B > A:
return output(0, 0, 0)
else:
print(f"[B={B}, n={n}]")
if (B - n) % 2 == 0:
E = gmpy2.mpz((B - n) / 2)
F = gmpy2.mpz(B + n + 1)
else:
E = gmpy2.mpz(B - n)
F = gmpy2.mpz((B + n + 1) / 2)
return output(A, E, F)
def output(A, E, F):
if A == 0:
print(f"Initial Value Error: Reset the B value")
else:
if A % E != 0 or A % F != 0 or A != E * F:
print(f"[Error Occurred] {A} != {E} * {F}")
else:
print(f"{A} = {E} * {F}")
return 0
if __name__ == '__main__':
if A >= 2:
timer_start = timeit.default_timer()
factor(A)
timer_stop = timeit.default_timer()
running_time = round(timer_stop - timer_start, 6)
print("running time: ", running_time, " seconds")
else:
print("undefined for A<2")
In my computer, this made the running time to be decreased as around 3 seconds from about 4 seconds. So I concluded that the reason for the multiprocessing version code being slower is due to this part
else:
D += k * n + (k * (k + 1)) / 2
n += k
where the code is constantly interpreting what the argument is and translating it as an actual integer.
To avoid this, the easiest way to do is making a several code, when doing parallel computation on 4 cores, as follows.
else:
D += n + 1
n += 1
else:
D += 2*n + 3
n += 2
else:
D += 3*n + 6
n += 3
else:
D += 4*n + 10
n += 4
Among them, only the "n += 3" one will not give a desired output since it is not divisible by 4. (Recall that 4 is a divisor of n=21739276 from our original code)
If there are only 4 cases to test, then you can just make 4 copies of similar code by your hand.
However, let's think about this code
import timeit
import gmpy2
import math
A = gmpy2.mpz(1000007777)
# Input a positive integer to factor.
# Put it inside the parentheses as "A = gmpy2.mpz(....)"
def factor(A):
B = gmpy2.mpz(math.sqrt(2 * A + 0.25) - 1)
D = gmpy2.mpz(A - (B * B + B) / 2)
while (D > 0):
B += 1
D = gmpy2.mpz(A - (B * B + B) / 2)
n = gmpy2.mpz(0)
while (D != 0 and B <= A):
if (D > 0):
B += 1
D -= B
else:
D += 11299*n+63839350
n += 11299
if B > A:
return output(0, 0, 0)
else:
print(f"[B={B}, n={n}]")
if (B - n) % 2 == 0:
E = gmpy2.mpz((B - n) / 2)
F = gmpy2.mpz(B + n + 1)
else:
E = gmpy2.mpz(B - n)
F = gmpy2.mpz((B + n + 1) / 2)
return output(A, E, F)
def output(A, E, F):
if A == 0:
print(f"Initial Value Error: Reset the B value")
else:
if A % E != 0 or A % F != 0 or A != E * F:
print(f"[Error Occurred] {A} != {E} * {F}")
else:
print(f"{A} = {E} * {F}")
return 0
if __name__ == '__main__':
if A >= 2:
timer_start = timeit.default_timer()
factor(A)
timer_stop = timeit.default_timer()
running_time = round(timer_stop - timer_start, 6)
print("running time: ", running_time, " seconds")
else:
print("undefined for A<2")
Note that 11299 is a divisor of n=21739276. Indeed, this has decreased the running time of the code from around 2 seconds from 4 seconds.
If we do the same job with subtract part
if (D > 0):
B += 1
D -= B
I'm sure the code shall be faster but I haven't tried this yet.
So, why do we need to do this? That is, why do we need to make multiple version of similar codes to do a task of this algorithm, instead of directly replacing the arguments with the divisor of n?
It is because, we don't know the B and n value before we try it.
(If you find a method to know them don't tell me, just publish it on some decent journal)
Therefore, unless we figure out any pattern of B and n values to be identified, I believe the best method at current stage is to make multiple copies of similar code to be executed.
Here is the organized question,
Is there any way to replace the 'actual lines' inside a code by following the number of cores to be used?
For example, if there is a desired answer for the question, when there is a original code which include some lines of code as follows,
else:
D += n + 1
n += 1
and applying the method of desired answer shall result in copying the following codes
else:
D += 2*n + 3
n += 2
else:
D += 3*n + 6
n += 3
else:
D += 4*n + 10
n += 4
which do the same task, but only those lines of code have been replaced. If the number of code has been increased to 6, then we will have two more codes to be added that will concurrently executed for doing the task.
else:
D += 5*n + 15
n += 5
else:
D += 6*n + 21
n += 6
To repeat, the 'actual lines' of the code shall be replaced with another 'actual lines' since the following code
else:
D += k * n + (k * (k + 1)) / 2
n += k
is not that helpful for doing the exhaustive task, because of its job of interpreting what the actual argument of k is.
I've tried to be as specific as possible to describe my problem. If you need more elaboration please let me have a chance to elaborate the problem via comments and edits. Thank you.
What I've tried
I've tried to do the similar task at Java. Since Java is well known for OOP, and I thought OOP might be a promising way to solve this problem. However, the problem that Java has, it is not designed for arithmetic. I've tried the BigInteger library but it was extremely slow in my numerical test, even more than Python.
The other possible method could be doing some Scanf job by one's hand for the whole number of the sequence of code I'm going to use to. However, even assuming this method works, if the number of cores to be used increase as thousands then the method would not be considered as the best solution to this.
We've shown that
else:
D += 11299*n+63839350
n += 11299
this code works faster than the previous codes. However for a bigger argument of A, we might need more than thousands, maybe millions of multi-cores, to do the task efficiently.
So I have concluded this method is not the best shot that we can try, leaving aside whether it actually works.
Edit
I wanted to engage on discussion as much as I can. However, because of some unfriendly behavior at the comments, I may refrain myself from doing that. (Really appreciate the answer though)
This could be my last edit in this post. I just wanted to point out, the fact that 11299 is a divisor of n=21739276 doesn't mean that we can't try more than that.
Note that n = 21739276 = 19276 (mod 30000). Then, by replacing that part of the code as follows
n = gmpy2.mpz(19276)
D += gmpy2.mpz(n * (n + 1) / 2)
while (D != 0 and B <= A):
if (D > 0):
B += 1
D -= B
else:
D += 30000*n+450015000
n += 30000
I could reduce the running time from around 2.4seconds to 2.1seconds. I expect the running time can be reduced more if I manipulate this subtraction part,
if (D > 0):
B += 1
D -= B
but I haven't tried yet. All of these elements were the motivation behind that I thought I needed to know how to do the effective parallel computation. As I said, I may not engage on further discussion unless definitely required. If you are interested, you may feel free to test and modify this code without noticing me.
a needlessly long question, but this is python ... you can generate code at runtime if you write the function as a string, and replace the parts you need with numbers from arguments, you can exec the code exactly as you want, but this is not pythonic or fastest.
if your "hot loop" is limited by calculating things that can be known beforehand then it's best to just calculate them before the loop.
k_local = k # magic trick, bind the global k to a local variable k_local to make lookup faster
second_term = (k_local * (k_local + 1)) / 2
while (D != 0 and B <= A):
if (D > 0):
B += 1
D -= B
else:
D += k_local * n + second_term
n += k_local
this has the EXACT same performance as
else:
D += 11299*n+63839350
n += 11299
one thing i can recommend, is to make all variables local, (make k an argument), and use cython to compile your functions to C, this way the compiler overhead is partially removed, and if you really want better performance you can use gmpy's cython "bindings" to manipulate it on C level and remove the interpreter overhead entirely (not the ABI overhead though)
if you really want to go one step further, you can rewrite this in C++ and get more performance, as gmpy is originally a C package, and you will be removing the ABI overhead, do this if you really want to squeeze the last drop of performance out of it, as your "hot loop" is probably too hot for python's virtual machine, that's trying to simulate a computer inside a computer (same to be said for java VM), rewriting this in C++ can be as much as 50 times faster than your current implementation, but the gap can be made as small as only 5 times if you use the previous suggestions.

How can I get the the recursion values to feed into the POWER FUNCTION?

So I have this function and I have done much of the work on it so far.
I am trying to feed the results from the addseries function into the power function to give me for example:
6^6 + 5^5 + 4^4 + 3^3 + 2^2 + 1+ 0 ..
I am having a problem with getting it to work. Any suggestions?
def power(n):
if(n<=0):
return 0
else:
return n**n
def addseries(num):
if(num == 0):
return 0
else:
print(num)
return sumseries(num - 1) + power(num)
Your code would actually work if you simply fix the indentation and typos (sumseries should be addseries, for example):
def power(n):
if(n<=0):
return 0
else:
return n**n
def addseries(num):
if(num == 0):
return 0
else:
return addseries(num - 1) + power(num)
so that:
print(addseries(6))
would output:
50069
which you can verify in Python shell:
>>> 1**1 + 2**2 + 3**3 + 4**4 + 5**5 + 6**6
50069
>>>
A bit simplified:
def addseries(num):
if(num == 0):
return 0
else:
print(num)
return num**num + addseries(num - 1)
Ignoring recursion:
n = 6
>>> sum(x ** x for x in range(n, 0, -1))
50069
# 6 ** 6 + 5 ** 5 + 4 ** 4 + 3 ** 3 + 2 ** 2 + 1 ** 1
# = 46656 + 3125 + 356 + 27 + 4 + 1
# = 50069
Using recursion:
def power_function(n):
if n < 1:
return 0
return n ** n + power_function(n - 1)
>>> power_function(6)
50069

Google python class [string2.py] exercise F

I've done the exercise and it works. But I want to know if there a smarter way to do it. Thanks.
# Consider dividing a string into two halves.
# If the length is even, the front and back halves are the same length.
# If the length is odd, we'll say that the extra char goes in the front half.
# e.g. 'abcde', the front half is 'abc', the back half 'de'.
# Given 2 strings, a and b, return a string of the form
# a-front + b-front + a-back + b-back
My code:
def front_back(a, b):
if len(a) % 2 == 0:
a_front = a[0:len(a) / 2]
else:
a_front = a[0:(len(a) / 2) + 1]
if len(a) % 2 == 0:
a_back = a[len(a) / 2:]
else:
a_back = a[(len(a) / 2) + 1:]
if len(b) % 2 == 0:
b_front = b[0:len(b) / 2]
else:
b_front = b[0:(len(b) / 2) + 1]
if len(b) % 2 == 0:
b_back = b[len(b) / 2:]
else:
b_back = b[(len(b) / 2) + 1:]
return a_front + b_front + a_back + b_back
You probably don't need all the if tests. Using substrings (as you use the slices in python), the following example in Java works.
public static String SplitMixCombine(String a, String b) {
return a.substring(0, (a.length()+1)/2) +
b.substring(0, (b.length()+1)/2) +
a.substring((a.length()+1)/2, a.length()) +
b.substring((b.length()+1)/2, b.length());
}
Just got this to work in python:
>>> def mix_combine(a, b):
... return a[0:int((len(a)+1)/2)] + b[0:int((len(b)+1)/2)] + a[int((len(a)+1)/2):] +b[int((len(b)+1)/2):]
...
>>> a = "abcd"
>>> b = "wxyz"
>>> mix_combine(a,b)
'abwxcdyz'
>>> a = "abcde"
>>> b = "vwxyz"
>>> mix_combine(a,b)
'abcvwxdeyz'
>>>
This is a lot cleaner code.
def front_back(a, b):
print a, b
a_indx = int((len(a)+1)/2)
b_indx = int((len(b)+1)/2)
print a[:a_indx] + b[:b_indx] + a[a_indx:] +b[b_indx:]
print "\n"
front_back("ab", "cd")
front_back("abc", "de")
front_back("ab", "cde")
front_back("abc", "def")
Hope this helps !
I wrote another one-liner for this:
def front_back(a, b):
return a[:len(a) / 2 + len(a) % 2] + b[:len(b) / 2 + len(b) % 2] + a[-(len(a) / 2):] + b[-(len(b) / 2):]
An interesting thing to note is that in Python 5 / 2 yields 2, but -5 / 2 yields -3, you might expect to get -2. That's why I added the parenthesis. See Negative integer division surprising result
def front_back(a, b):
return front_string(a)+front_string(b)+back_string(a)+back_string(b)
def front_string(s):
return s[:int((len(s)+1)/2)]
def back_string(s):
return s[int((len(s)+1)/2):]
# int((len(s)+1)/2) returns the correct index for both odd and even length strings

Decomposition function

I've been puzzling over how to get a certain function working in Python. The function itself is like this:
(Phi_m)x((n2)) = (Phi_m)(x(m*n + r)) = m*x[n1] + r*(x([n1] + 1) - x[n1])
Note: n here is just to specify some multiple. It is not a list element, but it becomes a list element when x is applied. In the below example For example, we might have that n is larger than any element on the list. E.g. a list has 9 elements, the largest is 3, and m=1 - here n=9 =/= element of the list.
where n2 and n1 are two different values of an input string, and where n1 is derived by 'decomposing' n2. We consider x[0] = 0, r is always at zero or positive and less than m, and all values of n (either of them) are positive integers. In general functional takes in a string of numbers and outputs another string. What normally happens is we fix an m, say m = 2. Now we decompose n2. Say n2 = 5. Then F(x(5)) = F(x(2*2+1)) 2x[2] + 1(x[3] - x[2]). So if our full input sequence was 0, 1, 1, 2, 3, 3 we'd have 2*1+0=2. So our fifth output term is 2.
I initially thought to do something like:
x = [0,1,1,2,3,3,3,3]
def F(n,j,r,x):
return j * x[n] + r(x[n + 1] - x[n])
for n in range(len(x) - 1):
print n
but this clearly fails for my purposes.
The thing is, for Python to do this it has to know how to decompose each number. So it knows 2 is fixed, and knows 2*3 is too much and so chooses 2*2. Then it has to know this is too little and add remainder 1. Only once it's done this can it actually grab n = 5. That is, it can run the function. It seems clear that once it knows how to do this it can just run through every n in our range, but I'm really not sure how to program the meat of this function.
here is how I would decompose a number in the form of n2 = m * n1 + r:
>>> def decompose(number):
... # returns a generator of tuples (m, n1, r)
... for m in range(1, number+1):
... yield m, number // m, number % m
...
>>> for m, n1, r in decompose(5):
... print "5 = %s * %s + %s" % (m, n1, r)
...
5 = 1 * 5 + 0
5 = 2 * 2 + 1
5 = 3 * 1 + 2
5 = 4 * 1 + 1
5 = 5 * 1 + 0
or with a fixed m, this is the same as a regular divmod:
>>> def decompose(number):
... return number // m, number % m
...
>>> m = 2
>>> n1, r = decompose(5)
>>> print "5 = %s * %s + %s" % (m, n1, r)
5 = 2 * 2 + 1
>>> m = 4
>>> n1, r = decompose(5)
>>> print "5 = %s * %s + %s" % (m, n1, r)
5 = 4 * 1 + 1
or more simply using lambda:
>>> decompose = lambda number: divmod(number, m)
>>>
>>> m = 2
>>> decompose(5)
(2, 1)
>>> m = 4
>>> decompose(5)
(1, 1)
and now, for a full exanple:
>>> decompose = lambda number: divmod(number, m)
>>>
>>> class Phi_m(list):
... def __init__(self, items):
... list.__init__(self)
... # you need to know at least m numbers.
... assert len(items) >= m, 'Not enough data'
... list.extend(self, items)
... # this is a sparse list
... # http://stackoverflow.com/questions/1857780/sparse-assignment-list-in-python
... def __setitem__(self, index, value):
... missing = index - len(self) + 1
... if missing > 0:
... self.extend([None] * missing)
... list.__setitem__(self, index, value)
... def __getitem__(self, index):
... try:
... value = list.__getitem__(self, index)
... if value is not None:
... # the item is in the list, yeah!
... return value
... # the item is in the list because it was resized
... # but it is None, so go on and calculate it.
... except IndexError:
... # the item is not in the list, calculate it.
... pass
... print 'calculating Fm[%s]' % index
... A, B = decompose(index)
... value1 = self.__getitem__(A)
... value2 = self.__getitem__(A + 1)
... print 'Fm[A=%s] = %s, Fm[A+1=%s] = %s' % (A, value1, A+1, value2)
... print 'back to calculating Fm[%s]' % index
... # m * x[n1] + r * (x[n1 + 1] - x[n1]) = (m - r) * x[n1] + r * x[n1 + 1]
... # A = n1 ; B = r ; value1 = x[n1] ; value2 = x[n+1]
... value = (m - B) * value1 + B * value2
... self.__setitem__(index, value)
... return value
...
>>> x = Phi_m([0, 1, 1])
>>>
>>> x[5]
calculating Fm[5]
calculating Fm[3]
Fm[A=1] = 1, Fm[A+1=2] = 1
back to calculating Fm[3]
Fm[A=2] = 1, Fm[A+1=3] = 2
back to calculating Fm[5]
3
>>>
>>>

Help me simplify this code (Python)

I'm a beginner in Python, teaching myself off of Google Code University. I had this problem as an exercise, and was able to solve it using the solution shown below:
# F. front_back
# Consider dividing a string into two halves.
# If the length is even, the front and back halves are the same length.
# If the length is odd, we'll say that the extra char goes in the front half.
# e.g. 'abcde', the front half is 'abc', the back half 'de'.
# Given 2 strings, a and b, return a string of the form
# a-front + b-front + a-back + b-back
def front_back(a, b):
if len(a) % 2 == 0:
ad = len(a) / 2
if len(b) % 2 == 0:
bd = len(b) / 2
else:
bd = (len(b) / 2) + 1
else:
ad = (len(a) / 2) + 1
if len(b) % 2 == 0:
bd = len(b) / 2
else:
bd = (len(b) / 2) + 1
return a[:ad] + b[:bd] + a[ad:] + b[bd:]
This produces the correct output and solves the problem. However, I am duplicating the logic of whether to split a string evenly or add the odd number to the first half, and this seems redundant. There has to be a more efficient way of doing this. The same exact check and logic is being applied to a and b. Anyone?
def front_back(a, b):
ad = (len(a) + 1) // 2
bd = (len(b) + 1) // 2
return a[:ad] + b[:bd] + a[ad:] + b[bd:]
Using // for division makes this code work in both Python 2.x and 3.x.
Well, put it in a separate function.
def front_back(string):
offset = len(string) / 2
if len(string) % 2 != 0:
offset += 1
return string[:offset], string[offset:]
def solution(a, b):
front_a, back_a = front_back(a)
front_b, back_b = front_back(b)
return front_a + back_a + front_b + back_b
Since you're adding 1 to the length if it's odd, and 'odd' means that len(a)%2 == 1...
def front_back2(a, b):
ad = (len(a) + len(a)%2) / 2
bd = (len(b) + len(b)%2) / 2
return a[:ad]+b[:bd]+a[ad:]+b[bd:]
Of course, you could even condense it to one line just for kicks (although, it's significantly less readable):
def front_back2(a, b):
return a[:(len(a)+len(a)%2)/2]+b[:(len(b)+len(b)%2)/2]+a[(len(a)+len(a)%2)/2:]+b[(len(b)+len(b)%2)/2:]
You can get the maximum index by using ceil
In [1]: l = [1,2,3]
In [2]: import math
In [4]: math.ceil(len(l)/2.0)
Out[4]: 2.0
In [5]: l.append(4)
In [6]: math.ceil(len(l)/2.0)
Out[6]: 2.0
In [7]: l.append(5)
In [8]: math.ceil(len(l)/2.0)
Out[8]: 3.0
In [9]: l[0:3]
Out[9]: [1, 2, 3]
In [10]: l[3:]
Out[10]: [4, 5]
Mhh trying to understand #Sven answer I got this:
len( s ) + 1 / 2
Will always give you the correct index.
So if we put that in a function:
def d( s ):
return ( len(s) + 1 ) / 2
We can use it in the solution:
def front_back( a, b ):
return a[:d(a)] + b[:d(b)] + a[d(a):] + b[d(b):]
Ok, I got it now.
I'm not quite sure what's the difference between / and // though
from math import ceil
def front_back(a, b):
divide = lambda s: int(ceil(len(s) / 2.0)) # or lambda s: (len(s) + 1) // 2
a_divide, b_divide = divide(a), divide(b)
return a[:a_divide] + b[:b_divide] + a[a_divide:] + b[b_divide:]
Here's mine:
def front_back( a, b ) :
return of(a)[0] + of(b)[0] + of(a)[1] + of(b)[1]
def of( s ):
index = len( s ) / 2 + ( 1 if len( s ) % 2 == 1 else 0 )
return ( s[ : index ] , s[ index : ] )
print front_back('abcde','hola')
Prints:
abchodela

Categories