Google python class [string2.py] exercise F - python

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

Related

Codewars. Some tests are passed, but i need to get tests which outputs the following mistake: 3263 should equal -1

Can you explain it what problems are here? To my mind, this code is like a heap of crap but with the right solving. I beg your pardon for my english.
the task of this kata:
Some numbers have funny properties. For example:
89 --> 8¹ + 9² = 89 * 1
695 --> 6² + 9³ + 5⁴= 1390 = 695 * 2
46288 --> 4³ + 6⁴+ 2⁵ + 8⁶ + 8⁷ = 2360688 = 46288 * 51
Given a positive integer n written as abcd... (a, b, c, d... being digits) and a positive integer p we want to find a positive integer k, if it exists, such as the sum of the digits of n taken to the successive powers of p is equal to k * n. In other words:
Is there an integer k such as : (a ^ p + b ^ (p+1) + c ^(p+2) + d ^ (p+3) + ...) = n * k
If it is the case we will return k, if not return -1.
Note: n, p will always be given as strictly positive integers.
dig_pow(89, 1) should return 1 since 8¹ + 9² = 89 = 89 * 1
dig_pow(92, 1) should return -1 since there is no k such as 9¹ + 2² equals 92 * k
dig_pow(695, 2) should return 2 since 6² + 9³ + 5⁴= 1390 = 695 * 2
dig_pow(46288, 3) should return 51 since 4³ + 6⁴+ 2⁵ + 8⁶ + 8⁷ = 2360688 = 46288 * 51
def dig_pow(n, p):
if n > 0 and p > 0:
b = []
a = str(n)
result = []
for i in a:
b.append(int(i))
for x in b:
if p != 1:
result.append(x ** p)
p += 1
else:
result.append(x ** (p + 1))
if int((sum(result)) / n) < 1:
return -1
elif int((sum(result)) / n) < 2:
return 1
else:
return int((sum(result)) / n)
test results:
Test Passed
Test Passed
Test Passed
Test Passed
3263 should equal -1
I don't know what exact version of Python you're using. This following code are in Python 3. And if I get you correctly, the code can be as simple as
def dig_pow(n, p):
assert n > 0 and p > 0
digits = (int(i) for i in str(n)) # replaces your a,b part with generator
result = 0 # you don't use result as a list, so an int suffice
for x in digits: # why do you need if in the loop? (am I missing something?)
result += x ** p
p += 1
if result % n: # you just test for divisibility
return -1
else:
return result // n
The major problem is that, in your objective, you have only two option of returning, but you wrote if elif else, which is definitely unnecessary and leads to problems and bugs. The % is modulus operator.
Also, having an if and not returning anything in the other branch is often not a good idea (see the assert part). Of course, if you don't like it, just fall back to if.
I believe this could work as well and I find it a little easier to read, however it can definitely be improved:
def dig_pow(n, p):
value = 0
for digit in str(n):
value += int(digit)**p
p += 1
for k in range(1,value):
if value/k == n:
return k
return -1
this is some example simple example than using:
digits = (int(i) for i in str(n))
I'm opting to use this version since I am still a beginner which can be done with this alt way:
result = 0
for digits in str(n):
#iterate through each digit from n
# single of digits turn to int & power to p
for number in digits:
result += int(number) ** p
p += 1
as for the full solution, it goes like this:
def dig_pow(n, p):
# example n = 123 , change it to string = 1, 2, 3
# each string[] **p, and p iterate by 1
# if n % p not equal to p return - 1
result = 0
for digits in str(n):
#iterate through each digit from n
# single digit turn to int & power to p
for number in digits:
result += int(number) ** p
p += 1
if result % n:
return -1
else:
return result // n

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

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.

Sum of even integers from a to b in Python

This is my code:
def sum_even(a, b):
count = 0
for i in range(a, b, 1):
if(i % 2 == 0):
count += [i]
return count
An example I put was print(sum_even(3,7)) and the output is 0. I cannot figure out what is wrong.
Your indentation is off, it should be:
def sum_even(a, b):
count = 0
for i in range(a, b, 1):
if(i % 2 == 0):
count += i
return count
so that return count doesn't get scoped to your for loop (in which case it would return on the 1st iteration, causing it to return 0)
(And change [i] to i)
NOTE: another problem - you should be careful about using range:
>>> range(3,7)
[3, 4, 5, 6]
so if you were to do calls to:
sum_even(3,7)
sum_even(3,8)
right now, they would both output 10, which is incorrect for sum of even integers between 3 and 8, inclusive.
What you really want is probably this instead:
def sum_even(a, b):
return sum(i for i in range(a, b + 1) if i % 2 == 0)
Move the return statement out of the scope of the for loop (otherwise you will return on the first loop iteration).
Change count += [i] to count += i.
Also (not sure if you knew this), range(a, b, 1) will contain all the numbers from a to b - 1 (not b). Moreover, you don't need the 1 argument: range(a,b) will have the same effect. So to contain all the numbers from a to b you should use range(a, b+1).
Probably the quickest way to add all the even numbers from a to b is
sum(i for i in xrange(a, b + 1) if not i % 2)
You can make it far simpler than that, by properly using the step argument to the range function.
def sum_even(a, b):
return sum(range(a + a%2, b + 1, 2))
You don't need the loop; you can use simple algebra:
def sum_even(a, b):
if (a % 2 == 1):
a += 1
if (b % 2 == 1):
b -= 1
return a * (0.5 - 0.25 * a) + b * (0.25 * b + 0.5)
Edit:
As NPE pointed out, my original solution above uses floating-point maths. I wasn't too concerned, since the overhead of floating-point maths is negligible compared with the removal of the looping (e.g. if calling sum_even(10, 10000)). Furthermore, the calculations use (negative) powers of two, so shouldn't be subject by rounding errors.
Anyhow, with the simple trick of multiplying everything by 4 and then dividing again at the end we can use integers throughout, which is preferable.
def sum_even(a, b):
if (a % 2 == 1):
a += 1
if (b % 2 == 1):
b -= 1
return (a * (2 - a) + b * (2 + b)) // 4
I'd like you see how your loops work if b is close to 2^32 ;-)
As Matthew said there is no loop needed but he does not explain why.
The problem is just simple arithmetic sequence wiki. Sum of all items in such sequence is:
(a+b)
Sn = ------- * n
2
where 'a' is a first item, 'b' is last and 'n' is number if items.
If we make 'a' and b' even numbers we can easily solve given problem.
So making 'a' and 'b' even is just:
if ((a & 1)==1):
a = a + 1
if ((b & 1)==1):
b = b - 1
Now think how many items do we have between two even numbers - it is:
b-a
n = --- + 1
2
Put it into equation and you get:
a+b b-a
Sn = ----- * ( ------ + 1)
2 2
so your code looks like:
def sum_even(a,b):
if ((a & 1)==1):
a = a + 1
if ((b & 1)==1):
b = b - 1
return ((a+b)/2) * (1+((b-a)/2))
Of course you may add some code to prevent a be equal or bigger than b etc.
Indentation matters in Python. The code you write returns after the first item processed.
This might be a simple way of doing it using the range function.
the third number in range is a step number, i.e, 0, 2, 4, 6...100
sum = 0
for even_number in range(0,102,2):
sum += even_number
print (sum)
def sum_even(a,b):
count = 0
for i in range(a, b):
if(i % 2 == 0):
count += i
return count
Two mistakes here :
add i instead of [i]
you return the value directly at the first iteration. Move the return count out of the for loop
The sum of all the even numbers between the start and end number (inclusive).
def addEvenNumbers(start,end):
total = 0
if end%2==0:
for x in range(start,end):
if x%2==0:
total+=x
return total+end
else:
for x in range(start,end):
if x%2==0:
total+=x
return total
print addEvenNumbers(4,12)
little bit more fancy with advanced python feature.
def sum(a,b):
return a + b
def evensum(a,b):
a = reduce(sum,[x for x in range(a,b) if x %2 ==0])
return a
SUM of even numbers including min and max numbers:
def sum_evens(minimum, maximum):
sum=0
for i in range(minimum, maximum+1):
if i%2==0:
sum = sum +i
i= i+1
return sum
print(sum_evens(2, 6))
OUTPUT is : 12
sum_evens(2, 6) -> 12 (2 + 4 + 6 = 12)
List based approach,
Use b+1 if you want to include last value.
def sum_even(a, b):
even = [x for x in range (a, b) if x%2 ==0 ]
return sum(even)
print(sum_even(3,6))
4
[Program finished]
This will add up all your even values between 1 and 10 and output the answer which is stored in the variable x
x = 0
for i in range (1,10):
if i %2 == 0:
x = x+1
print(x)

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

Average of two strings in alphabetical/lexicographical order

Suppose you take the strings 'a' and 'z' and list all the strings that come between them in alphabetical order: ['a','b','c' ... 'x','y','z']. Take the midpoint of this list and you find 'm'. So this is kind of like taking an average of those two strings.
You could extend it to strings with more than one character, for example the midpoint between 'aa' and 'zz' would be found in the middle of the list ['aa', 'ab', 'ac' ... 'zx', 'zy', 'zz'].
Might there be a Python method somewhere that does this? If not, even knowing the name of the algorithm would help.
I began making my own routine that simply goes through both strings and finds midpoint of the first differing letter, which seemed to work great in that 'aa' and 'az' midpoint was 'am', but then it fails on 'cat', 'doggie' midpoint which it thinks is 'c'. I tried Googling for "binary search string midpoint" etc. but without knowing the name of what I am trying to do here I had little luck.
I added my own solution as an answer
If you define an alphabet of characters, you can just convert to base 10, do an average, and convert back to base-N where N is the size of the alphabet.
alphabet = 'abcdefghijklmnopqrstuvwxyz'
def enbase(x):
n = len(alphabet)
if x < n:
return alphabet[x]
return enbase(x/n) + alphabet[x%n]
def debase(x):
n = len(alphabet)
result = 0
for i, c in enumerate(reversed(x)):
result += alphabet.index(c) * (n**i)
return result
def average(a, b):
a = debase(a)
b = debase(b)
return enbase((a + b) / 2)
print average('a', 'z') #m
print average('aa', 'zz') #mz
print average('cat', 'doggie') #budeel
print average('google', 'microsoft') #gebmbqkil
print average('microsoft', 'google') #gebmbqkil
Edit: Based on comments and other answers, you might want to handle strings of different lengths by appending the first letter of the alphabet to the shorter word until they're the same length. This will result in the "average" falling between the two inputs in a lexicographical sort. Code changes and new outputs below.
def pad(x, n):
p = alphabet[0] * (n - len(x))
return '%s%s' % (x, p)
def average(a, b):
n = max(len(a), len(b))
a = debase(pad(a, n))
b = debase(pad(b, n))
return enbase((a + b) / 2)
print average('a', 'z') #m
print average('aa', 'zz') #mz
print average('aa', 'az') #m (equivalent to ma)
print average('cat', 'doggie') #cumqec
print average('google', 'microsoft') #jlilzyhcw
print average('microsoft', 'google') #jlilzyhcw
If you mean the alphabetically, simply use FogleBird's algorithm but reverse the parameters and the result!
>>> print average('cat'[::-1], 'doggie'[::-1])[::-1]
cumdec
or rewriting average like so
>>> def average(a, b):
... a = debase(a[::-1])
... b = debase(b[::-1])
... return enbase((a + b) / 2)[::-1]
...
>>> print average('cat', 'doggie')
cumdec
>>> print average('google', 'microsoft')
jlvymlupj
>>> print average('microsoft', 'google')
jlvymlupj
It sounds like what you want, is to treat alphabetical characters as a base-26 value between 0 and 1. When you have strings of different length (an example in base 10), say 305 and 4202, your coming out with a midpoint of 3, since you're looking at the characters one at a time. Instead, treat them as a floating point mantissa: 0.305 and 0.4202. From that, it's easy to come up with a midpoint of .3626 (you can round if you'd like).
Do the same with base 26 (a=0...z=25, ba=26, bb=27, etc.) to do the calculations for letters:
cat becomes 'a.cat' and doggie becomes 'a.doggie', doing the math gives cat a decimal value of 0.078004096, doggie a value of 0.136390697, with an average of 0.107197397 which in base 26 is roughly "cumcqo"
Based on your proposed usage, consistent hashing ( http://en.wikipedia.org/wiki/Consistent_hashing ) seems to make more sense.
Thanks for everyone who answered, but I ended up writing my own solution because the others weren't exactly what I needed. I am trying to average app engine key names, and after studying them a bit more I discovered they actually allow any 7-bit ASCII characters in the names. Additionally I couldn't really rely on the solutions that converted the key names first to floating point, because I suspected floating point accuracy just isn't enough.
To take an average, first you add two numbers together and then divide by two. These are both such simple operations that I decided to just make functions to add and divide base 128 numbers represented as lists. This solution hasn't been used in my system yet so I might still find some bugs in it. Also it could probably be a lot shorter, but this is just something I needed to get done instead of trying to make it perfect.
# Given two lists representing a number with one digit left to decimal point and the
# rest after it, for example 1.555 = [1,5,5,5] and 0.235 = [0,2,3,5], returns a similar
# list representing those two numbers added together.
#
def ladd(a, b, base=128):
i = max(len(a), len(b))
lsum = [0] * i
while i > 1:
i -= 1
av = bv = 0
if i < len(a): av = a[i]
if i < len(b): bv = b[i]
lsum[i] += av + bv
if lsum[i] >= base:
lsum[i] -= base
lsum[i-1] += 1
return lsum
# Given a list of digits after the decimal point, returns a new list of digits
# representing that number divided by two.
#
def ldiv2(vals, base=128):
vs = vals[:]
vs.append(0)
i = len(vs)
while i > 0:
i -= 1
if (vs[i] % 2) == 1:
vs[i] -= 1
vs[i+1] += base / 2
vs[i] = vs[i] / 2
if vs[-1] == 0: vs = vs[0:-1]
return vs
# Given two app engine key names, returns the key name that comes between them.
#
def average(a_kn, b_kn):
m = lambda x:ord(x)
a = [0] + map(m, a_kn)
b = [0] + map(m, b_kn)
avg = ldiv2(ladd(a, b))
return "".join(map(lambda x:chr(x), avg[1:]))
print average('a', 'z') # m#
print average('aa', 'zz') # n-#
print average('aa', 'az') # am#
print average('cat', 'doggie') # d(mstr#
print average('google', 'microsoft') # jlim.,7s:
print average('microsoft', 'google') # jlim.,7s:
import math
def avg(str1,str2):
y = ''
s = 'abcdefghijklmnopqrstuvwxyz'
for i in range(len(str1)):
x = s.index(str2[i])+s.index(str1[i])
x = math.floor(x/2)
y += s[x]
return y
print(avg('z','a')) # m
print(avg('aa','az')) # am
print(avg('cat','dog')) # chm
Still working on strings with different lengths... any ideas?
This version thinks 'abc' is a fraction like 0.abc. In this approach space is zero and a valid input/output.
MAX_ITER = 10
letters = " abcdefghijklmnopqrstuvwxyz"
def to_double(name):
d = 0
for i, ch in enumerate(name):
idx = letters.index(ch)
d += idx * len(letters) ** (-i - 1)
return d
def from_double(d):
name = ""
for i in range(MAX_ITER):
d *= len(letters)
name += letters[int(d)]
d -= int(d)
return name
def avg(w1, w2):
w1 = to_double(w1)
w2 = to_double(w2)
return from_double((w1 + w2) * 0.5)
print avg('a', 'a') # 'a'
print avg('a', 'aa') # 'a mmmmmmmm'
print avg('aa', 'aa') # 'a zzzzzzzz'
print avg('car', 'duck') # 'cxxemmmmmm'
Unfortunately, the naïve algorithm is not able to detect the periodic 'z's, this would be something like 0.99999 in decimal; therefore 'a zzzzzzzz' is actually 'aa' (the space before the 'z' periodicity must be increased by one.
In order to normalise this, you can use the following function
def remove_z_period(name):
if len(name) != MAX_ITER:
return name
if name[-1] != 'z':
return name
n = ""
overflow = True
for ch in reversed(name):
if overflow:
if ch == 'z':
ch = ' '
else:
ch=letters[(letters.index(ch)+1)]
overflow = False
n = ch + n
return n
print remove_z_period('a zzzzzzzz') # 'aa'
I haven't programmed in python in a while and this seemed interesting enough to try.
Bear with my recursive programming. Too many functional languages look like python.
def stravg_half(a, ln):
# If you have a problem it will probably be in here.
# The floor of the character's value is 0, but you may want something different
f = 0
#f = ord('a')
L = ln - 1
if 0 == L:
return ''
A = ord(a[0])
return chr(A/2) + stravg_half( a[1:], L)
def stravg_helper(a, b, ln, x):
L = ln - 1
A = ord(a[0])
B = ord(b[0])
D = (A + B)/2
if 0 == L:
if 0 == x:
return chr(D)
# NOTE: The caller of helper makes sure that len(a)>=len(b)
return chr(D) + stravg_half(a[1:], x)
return chr(D) + stravg_helper(a[1:], b[1:], L, x)
def stravg(a, b):
la = len(a)
lb = len(b)
if 0 == la:
if 0 == lb:
return a # which is empty
return stravg_half(b, lb)
if 0 == lb:
return stravg_half(a, la)
x = la - lb
if x > 0:
return stravg_helper(a, b, lb, x)
return stravg_helper(b, a, la, -x) # Note the order of the args

Categories