Random picking of operators (add,sub) with conditions - python

import operator
import random
# these modules will help with the random picking of operators
ops = {"+": operator.add, "-": operator.sub}
a = ["+", "-"] #this is to do the random.choice() function
b = float(ops[random.choice(a)](0, 1)) #these can only take 2 parameters, don't ask me why
c = float(ops[random.choice(a)](2, 3))
d = float(ops[random.choice(a)](4, 5))
e = float(ops[random.choice(a)](6, 7))
f = float(ops[random.choice(a)](8, 9))
print(b+c+d+e+f) #I have no idea how to do random operators here so i just added
while b+c+d+e+f != 5: #to over and over until i get 5
if b+c+d+e+f == 5: #if that finally happens...
print(b+c+d+e+f) #print 5
So the idea is to use random operators between numbers 0-9 to get 5.
I literally don't know what code to use. The operator.add() function only take 2 parameters.
if anybody can give me an idea how to enter more parameters, That would really help.
To put it simply, the numbers 0,1,2,3,4,5,6,7,8,9 need to have + or minus go between each number, to get the number 5.

This is probably not the most efficient or elegant method, but it will do the trick. Always put your while loop around what needs to be done. In your example, only b+c+d+e+f is only calculated over and over again while the operators and values for b, c, d, e and f do not change.
import random
result = 0
result_str = ""
while result != 5:
result = 0
result_str = ""
for i in range(0,10):
# here is random decision between operators
if bool(random.getrandbits(1)):
result += i
result_str = result_str + "+" + str(i)
else:
result -= i
result_str = result_str + "-" + str(i)
print(result_str)

Related

Quadratic Formula in Python

Here is my quadratic formula code. You enter in the full equation, and it outputs the roots. The problem is, my code fully depends on the index spot of where the number is in the list, and if I were to miss a space somewhere while writing my code, it would not work. Anyone know how to fix this?
import re
import cmath
quadratic = str(input('Enter a quadratic equation (in the form of ax^2 + bx + c): '))
split_qua = re.split(' | x |', quadratic)
a1 = (split_qua[1])
b1 = (split_qua[8])
c1 = (split_qua[13])
a = int(a1)
b = int(b1)
c = int(c1)
def roots(a,b,c):
dis = b*b-4*a*c
if dis >=0:
root1 =(-b + cmath.sqrt(dis) / 2*a)
root2 =(-b - cmath.sqrt(dis) / 2*a)
return root1, root2
elif dis < 0:
return 'This does not work. There is no roots'
print(roots(a,b,c))
You could try removing all the spaces and then parsing your input string:
a,b,c = map(int, [s.split("x")[0] for s in quadratic.replace(" ","").split("+")])
Here's a brute force parser that ignores spaces and handles signs and floats. It will also handle missing values (3x^2-9).
def parse_equation(s):
nums = [0,0,0]
accum = ''
expo = False
sign = 1
for c in s:
if expo and c == '2':
expo = False
nums[0] = nums[1]
nums[1] = 0
accum = ''
elif c in '1234567890.':
accum += c
elif c == 'x':
nums[1] = float(accum) * sign
accum = ''
elif c == '+':
sign = 1
elif c == '-':
sign = -1
elif c == '^':
expo = True
nums[2] = float(accum) * sign
return nums
for test in (
'3x^2+4x-3',
'3x^2 + 4x - 3',
'-19.5 x^2 + 7.5 x - 3'
):
print(test, parse_equation(test))
Output:
3x^2+4x-3 [3.0, 4.0, -3.0]
3x^2 + 4x - 3 [3.0, 4.0, -3.0]
-19.5 x^2 + 7.5 x - 3 [-19.5, 7.5, -3.0]
You can extract the numbers and check the equation structure in one regex expression
import re
import cmath
quadratic = str(input('Enter a quadratic equation (in the form of ax^2 + bx + c): '))
parts = re.findall(r'(\d+)x\^2\s*\+\s*(\d+)x\s*\+\s*(\d+)', quadratic)
try:
a, b, c = [int(x) for x in parts[0]]
except:
raise RuntimeError('Incorrect equation')
def roots(a, b, c):
dis = b * b - 4 * a * c
if dis >= 0:
root1 = (-b + cmath.sqrt(dis) / 2 * a)
root2 = (-b - cmath.sqrt(dis) / 2 * a)
return root1, root2
elif dis < 0:
return 'This does not work. There is no roots'
print(roots(a, b, c))
Output:
Enter a quadratic equation (in the form of ax^2 + bx + c): 4x^2 + 8x + 1
((5.8564064605510175+0j), (-21.856406460551018+0j))
You're running into a problem with your regular expression on this line:
split_qua = re.split(' | x |', quadratic)
I'm not entirely sure how you came up with that regex, but it's effectively splitting the string in any of the following situations:
Between spaces
Between any occurrence of the string " x " (that's an "x" with a space on either side)
Between all characters
Situation #3 is always going to win.
Without getting too much into the syntax of regular expressions--a topic that you may want to research on your own--all of the characters in your regex are being taken literally except the vertical bar (|). That is effectively acting as an "or" operator: split between " " or " x " or "". That last one is giving you trouble.
The ideal solution here would be to parse everything properly rather than using regular expressions; however, since this is likely just a quick script for personal use, you can certainly craft a better regex. It won't be ideal, but it'll likely work well enough for your purposes. For example:
split_qua = re.fullmatch(r'([+-]?\d+)?x\^2([+-]\d+)?x([+-]\d+)?', quadratic.replace(' ', ''))
a = int(split_qua[1] or 1)
b = int(split_qua[2] or 1)
c = int(split_qua[3] or 0)
Let's break down the regex:
This isn't actually part of the regex, but notice that we're calling replace() to remove all the whitespace. This just allows us to use a simpler regex, since we don't need to worry about parsing spaces.
Each number in which we're interested is parsed via ([+-]?\d+) or ([+-]\d+). The first one is used when we don't know whether there will be a sign; that only happens for a.
The parentheses are used for grouping; the first set of parentheses will be stored in split_qua[1] and so on.
[+-] means "either + or -"
? means the previous token is optional--in this case, it means the sign is optional
\d means "any digit"
+ means "repeated one or more times," that way we can have numbers that are more than one digit long
x matches the literal character "x"
\^ matches the literal character "^". Carets have a special meaning in regular expressions, so we have to escape them.
The ? following clothing parenthesis of each group indicates that it's optional. If a or b are omitted, we'll assume their value is 1; if c is omitted, we'll assume its value is 0.
This technique is far from perfect: in particular, it can't parse expressions in which one of the first two terms is omitted. For example, 3x^2 + 1 will fail to parse. It's up to you whether this is worth handling; if it is, you should investigate using proper parsing logic rather than regular expressions. If this doesn't matter to you, the regular expression here may be sufficient.
You can do like this.
Remove the spaces from the input using .replace()
Split the string at + to get individual strings.
a,b,c = quadratic.replace(" ","").split('+')
Strip off the powers of x from the individual strings using
rstrip() and convert them to Integers.
a = int(a.rstrip('x^2'))
b = int(b.rstrip('x'))
c = int(c)
Here is the full code:
import cmath
quadratic = str(input('Enter a quadratic equation (in the form of ax^2 + bx + c): '))
a,b,c = quadratic.replace(" ","").split('+')
a = int(a.rstrip('x^2'))
b = int(b.rstrip('x'))
c = int(c)
def roots(a,b,c):
dis = b*b-4*a*c
if dis >=0:
root1 =(-b + cmath.sqrt(dis) / 2*a)
root2 =(-b - cmath.sqrt(dis) / 2*a)
return root1, root2
elif dis < 0:
return 'This does not work. There is no roots'
print(roots(a,b,c))

Can anyone tell me the issue with my logic for this HackerRank question? (Repeated String, Link in Description)

This code keeps messing up on weird edge cases but I don't see how it's wrong. It works for about half the cases given on the site, but will be off by 2 for some of the larger cases. The basic logic of the code is (1) Find the number of a's in a single instance of the string (2) Multiply that number by the number of times the string goes into n (3) Get the number of a's in the last occurrence of the string that did not fit into n.
https://www.hackerrank.com/challenges/repeated-string/problem
#/bin/python3
import math
import os
import random
import re
import sys
#Complete the repeatedString function below.
def repeatedString(s, n):
total_a = 0
#Get number of a's in one instance of the string
string_a = 0
for i in range(len(s)):
if s[i] == 'a':
string_a += 1
#Get number of times whole string occurs and multiply with a's in single string
total_a = string_a * n//len(s)
#Get remainder a's
chars_left = n%len(s)
s2 = s[:chars_left]
for i in range(len(s2)):
if s2[i] == 'a':
total_a += 1
return total_a
if __name__ == '__main__':
fptr = open(os.environ['OUTPUT_PATH'], 'w')
s = input()
n = int(input())
result = repeatedString(s, n)
fptr.write(str(result) + '\n')
fptr.close()
The problem is with total_a = string_a * n//len(s)
replace with total_a = string_a * (n//len(s)).
In your case * is evaluating first
Python Operators Precedence:
* / % // + -
More clean code:
def repeatedString(s, n):
return s.count('a') * (n//len(s)) + s[:n%len(s)].count('a')

How to create an iterator with Python itertools that returns progressively larger repeats? [duplicate]

I would like to make a alphabetical list for an application similar to an excel worksheet.
A user would input number of cells and I would like to generate list.
For example a user needs 54 cells. Then I would generate
'a','b','c',...,'z','aa','ab','ac',...,'az', 'ba','bb'
I can generate the list from [ref]
from string import ascii_lowercase
L = list(ascii_lowercase)
How do i stitch it together?
A similar question for PHP has been asked here. Does some one have the python equivalent?
Use itertools.product.
from string import ascii_lowercase
import itertools
def iter_all_strings():
for size in itertools.count(1):
for s in itertools.product(ascii_lowercase, repeat=size):
yield "".join(s)
for s in iter_all_strings():
print(s)
if s == 'bb':
break
Result:
a
b
c
d
e
...
y
z
aa
ab
ac
...
ay
az
ba
bb
This has the added benefit of going well beyond two-letter combinations. If you need a million strings, it will happily give you three and four and five letter strings.
Bonus style tip: if you don't like having an explicit break inside the bottom loop, you can use islice to make the loop terminate on its own:
for s in itertools.islice(iter_all_strings(), 54):
print s
You can use a list comprehension.
from string import ascii_lowercase
L = list(ascii_lowercase) + [letter1+letter2 for letter1 in ascii_lowercase for letter2 in ascii_lowercase]
Following #Kevin 's answer :
from string import ascii_lowercase
import itertools
# define the generator itself
def iter_all_strings():
size = 1
while True:
for s in itertools.product(ascii_lowercase, repeat=size):
yield "".join(s)
size +=1
The code below enables one to generate strings, that can be used to generate unique labels for example.
# define the generator handler
gen = iter_all_strings()
def label_gen():
for s in gen:
return s
# call it whenever needed
print label_gen()
print label_gen()
print label_gen()
I've ended up doing my own.
I think it can create any number of letters.
def AA(n, s):
r = n % 26
r = r if r > 0 else 26
n = (n - r) / 26
s = chr(64 + r) + s
if n > 26:
s = AA(n, s)
elif n > 0:
s = chr(64 + n) + s
return s
n = quantity | r = remaining (26 letters A-Z) | s = string
To print the list :
def uprint(nc):
for x in range(1, nc + 1):
print AA(x,'').lower()
Used VBA before convert to python :
Function AA(n, s)
r = n Mod 26
r = IIf(r > 0, r, 26)
n = (n - r) / 26
s = Chr(64 + r) & s
If n > 26 Then
s = AA(n, s)
ElseIf n > 0 Then
s = Chr(64 + n) & s
End If
AA = s
End Function
Using neo's insight on a while loop.
For a given iterable with chars in ascending order. 'abcd...'.
n is the Nth position of the representation starting with 1 as the first position.
def char_label(n, chars):
indexes = []
while n:
residual = n % len(chars)
if residual == 0:
residual = len(chars)
indexes.append(residual)
n = (n - residual)
n = n // len(chars)
indexes.reverse()
label = ''
for i in indexes:
label += chars[i-1]
return label
Later you can print a list of the range n of the 'labels' you need using a for loop:
my_chrs = 'abc'
n = 15
for i in range(1, n+1):
print(char_label(i, my_chrs))
or build a list comprehension etc...
Print the set of xl cell range of lowercase and uppercase charterers
Upper_case:
from string import ascii_uppercase
import itertools
def iter_range_strings(start_colu):
for size in itertools.count(1):
for string in itertools.product(ascii_uppercase, repeat=size):
yield "".join(string)
input_colume_range = ['A', 'B']
input_row_range= [1,2]
for row in iter_range_strings(input_colume_range[0]):
for colum in range(int(input_row_range[0]), int(input_row_range[1]+1)):
print(str(row)+ str(colum))
if row == input_colume_range[1]:
break
Result:
A1
A2
B1
B2
In two lines (plus an import):
from string import ascii_uppercase as ABC
count = 100
ABC+=' '
[(ABC[x[0]] + ABC[x[1]]).strip() for i in range(count) if (x:= divmod(i-26, 26))]
Wrap it in a function/lambda if you need to reuse.
code:
alphabet = ["a","b","c","d","e","f","g","h","i","j","k","l","m","n","o","p","q","r","s","t","u","v","w","x","y","z"]
for i in range(len(alphabet)):
for a in range(len(alphabet)):
print(alphabet[i] + alphabet[a])
result:
aa
ab
ac
ad
ae
af
ag
ah
ai
aj
ak
al
am
...

Optimizing python code

Any tips on optimizing this python code for finding next palindrome:
Input number can be of 1000000 digits
COMMENTS ADDED
#! /usr/bin/python
def inc(lst,lng):#this function first extract the left half of the string then
#convert it to int then increment it then reconvert it to string
#then reverse it and finally append it to the left half.
#lst is input number and lng is its length
if(lng%2==0):
olst=lst[:lng/2]
l=int(lng/2)
olst=int(olst)
olst+=1
olst=str(olst)
p=len(olst)
if l<p:
olst2=olst[p-2::-1]
else:
olst2=olst[::-1]
lst=olst+olst2
return lst
else:
olst=lst[:lng/2+1]
l=int(lng/2+1)
olst=int(olst)
olst+=1
olst=str(olst)
p=len(olst)
if l<p:
olst2=olst[p-3::-1]
else:
olst2=olst[p-2::-1]
lst=olst+olst2
return lst
t=raw_input()
t=int(t)
while True:
if t>0:
t-=1
else:
break
num=raw_input()#this is input number
lng=len(num)
lst=num[:]
if(lng%2==0):#this if find next palindrome to num variable
#without incrementing the middle digit and store it in lst.
olst=lst[:lng/2]
olst2=olst[::-1]
lst=olst+olst2
else:
olst=lst[:lng/2+1]
olst2=olst[len(olst)-2::-1]
lst=olst+olst2
if int(num)>=int(lst):#chk if lst satisfies criteria for next palindrome
num=inc(num,lng)#otherwise call inc function
print num
else:
print lst
I think most of the time in this code is spent converting strings to integers and back. The rest is slicing strings and bouncing around in the Python interpreter. What can be done about these three things? There are a few unnecessary conversions in the code, which we can remove. I see no way to avoid the string slicing. To minimize your time in the interpreter you just have to write as little code as possible :-) and it also helps to put all your code inside functions.
The code at the bottom of your program, which takes a quick guess to try and avoid calling inc(), has a bug or two. Here's how I might write that part:
def nextPal(num):
lng = len(num)
guess = num[:lng//2] + num[(lng-1)//2::-1] # works whether lng is even or odd
if guess > num: # don't bother converting to int
return guess
else:
return inc(numstr, n)
This simple change makes your code about 100x faster for numbers where inc doesn't need to be called, and about 3x faster for numbers where it does need to be called.
To do better than that, I think you need to avoid converting to int entirely. That means incrementing the left half of the number without using ordinary Python integer addition. You can use an array and carry out the addition algorithm "by hand":
import array
def nextPal(numstr):
# If we don't need to increment, just reflect the left half and return.
n = len(numstr)
h = n//2
guess = numstr[:n-h] + numstr[h-1::-1]
if guess > numstr:
return guess
# Increment the left half of the number without converting to int.
a = array.array('b', numstr)
zero = ord('0')
ten = ord('9') + 1
for i in range(n - h - 1, -1, -1):
d = a[i] + 1
if d == ten:
a[i] = zero
else:
a[i] = d
break
else:
# The left half was all nines. Carry the 1.
# Update n and h since the length changed.
a.insert(0, ord('1'))
n += 1
h = n//2
# Reflect the left half onto the right half.
a[n-h:] = a[h-1::-1]
return a.tostring()
This is another 9x faster or so for numbers that require incrementing.
You can make this a touch faster by using a while loop instead of for i in range(n - h - 1, -1, -1), and about twice as fast again by having the loop update both halves of the array rather than just updating the left-hand half and then reflecting it at the end.
You don't have to find the palindrome, you can just generate it.
Split the input number, and reflect it. If the generated number is too small, then increment the left hand side and reflect it again:
def nextPal(n):
ns = str(n)
oddoffset = 0
if len(ns) % 2 != 0:
oddoffset = 1
leftlen = len(ns) / 2 + oddoffset
lefts = ns[0:leftlen]
right = lefts[::-1][oddoffset:]
p = int(lefts + right)
if p < n:
## Need to increment middle digit
left = int(lefts)
left += 1
lefts = str(left)
right = lefts[::-1][oddoffset:]
p = int(lefts + right)
return p
def test(n):
print n
p = nextPal(n)
assert p >= n
print p
test(1234567890)
test(123456789)
test(999999)
test(999998)
test(888889)
test(8999999)
EDIT
NVM, just look at this page: http://thetaoishere.blogspot.com/2009/04/finding-next-palindrome-given-number.html
Using strings. n >= 0
from math import floor, ceil, log10
def next_pal(n):
# returns next palindrome, param is an int
n10 = str(n)
m = len(n10) / 2.0
s, e = int(floor(m - 0.5)), int(ceil(m + 0.5))
start, middle, end = n10[:s], n10[s:e], n10[e:]
assert (start, middle[0]) == (end[-1::-1], middle[-1]) #check that n is actually a palindrome
r = int(start + middle[0]) + 1 #where the actual increment occurs (i.e. add 1)
r10 = str(r)
i = 3 - len(middle)
if len(r10) > len(start) + 1:
i += 1
return int(r10 + r10[-i::-1])
Using log, more optized. n > 9
def next_pal2(n):
k = log10(n + 1)
l = ceil(k)
s, e = int(floor(l/2.0 - 0.5)), int(ceil(l/2.0 + 0.5))
mmod, emod = 10**(e - s), int(10**(l - e))
start, end = divmod(n, emod)
start, middle = divmod(start, mmod)
r1 = 10*start + middle%10 + 1
i = middle > 9 and 1 or 2
j = s - i + 2
if k == l:
i += 1
r2 = int(str(r1)[-i::-1])
return r1*10**j + r2

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