Decomposition function - python

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
>>>
>>>

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

Generate x+xx+xxx+xxxx ... for a given integer (for 4 -> 4+44+444...)

I have to incrementally concatenate a given number on each iteration so that it returns a sum and the concatenated string. This is my try:
def digit_sum_from_letters(x):
a = int("%s" % x)
b = int("%s%s" % (x,x))
c = int("%s%s%s" % (x,x,x))
d = int("%s%s%s%s" % (x,x,x,x))
return a+b+c+d
print digit_sum_from_letters(9)
returning 11106
But I need to generate the sum for whatever given integer so I need a loop but I'm stuck.
Thanks!
This should work:
>>> def digit_sum(x):
lst = [str(x)*i for i in range(1,x+1)]
print '+'.join(lst)
return sum(map(int, lst))
>>> digit_sum(7)
7+77+777+7777+77777+777777+7777777
8641969
>>> digit_sum(9)
9+99+999+9999+99999+999999+9999999+99999999+999999999
1111111101
>>> digit_sum(3)
3+33+333
369
Given digit and n (for example, digit=4 and n=3 is 4 + 44 + 444), you just need generate a sequence of ones, and multiply its sum by digit.
digit = 4
n = 3
# 1, 11, 111
ones = [ int("1" * i) for i in range(1, n+1)]
# 4 + 44 + 444 = 4 * (1 + 11 + 111)
answer = digit * sum(ones)
There's a couple of ways to do this. I'll start with the solution most similar to yours, and if you want I can introduce a likely faster way :).
def digit_sum_from_letters(digit,count):
suma=0
cur=digit
for _ in xrange(count):
suma+=int(cur)
cur+=digit
return suma
Just for fun:
def f(n):
return n*int("123456789"[:n])
It gives:
1 -> 1
2 -> 24
3 -> 369
4 -> 4936
5 -> 61725
6 -> 740736
7 -> 8641969
8 -> 98765424
9 -> 1111111101
Who told you you need a loop? Don't listen to them
def fn(n):
x,z = n,10
return x*(z*(z**n-1) // (z-1) - n) // (z-1)
print(fn(1)) # 1
print(fn(2)) # 24
print(fn(3)) # 369
print(fn(4)) # 4936
EDIT: It's a shame they require you the expression string too. On that part you must use a loop sadly
Following function will do, n is your number(4) m is number of iterations(4, 44, 444, 4444, ...).
def digit_sum_from_letters(n, m):
sum = 0
# this is the multiplier.
# throughout the iterations it will be 1, 11, 111, 1111 ...
currMult = 1
for i in range(0,m):
sum += n*currMult
currMult = currMult*10 + 1
return sum
Example run:
>>> sumLetters(9,4 )
11106
>>>
def sum_n(x, n):
s = 0
for i in range(1,n+1):
s += int(('%d'*i) % tuple([x]*i))
return s
In [0]: print(sum_n(9,4))
Out[0]: 11106
You can do it using list compression:
x = 9
c = 4
sum([int(str(x) * i) for i in xrange(1,c + 1)])
11106

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.

How to implement base b expansion in Python?

I have to implement this pseudo-code (from a discrete math book):
procedure base b expansion(n,b: positive integers with b>1
q :=n
k :=0
while q does not equal 0
a_k := q mod b
q = q div b
k = k + 1
return (a_k-1, .... a_1, a_0) {(a_k-1... a_1a_0)_b is the base expansion of n}
Here is my code thus far:
def expansion(n,b):
q = n
k = 0
a = []
i = len(str(n))
for x in range(0,1000):
a.append(0)
while q != 0:
a[k] = q % b
q = q / b
return a[k]
print expansion(444,2)
I just cant figure out what I am doing wrong, it usually says the index is out of bounds or it doesn't print enough numbers.
In your code you are not updating k,
while q != 0:
a[k] = q % b
q = q / b
# You need to update k
k += 1
Also, you need to return only a, not a[k].
Also, understand that for the current argument (444,2) you need at least 1085 places in the array before q becomes zero. You do not need to assign based on an index, but rather append the values to the list as they are computed.
So,
def expansion(n,b):
q = n
k = 0
a = []
i = len(str(n))
while q != 0:
a.append(q % b)
q = q / b
k += 1
return a
This way you avoid having to allocate places before hand.
Rather than using a list to accumulate digits, try a string. As you get a digit, concatenate it to the front of the string. Like so:
>>> def n_as_base_b(n, b):
... output = ""
... while n >0:
... output = str(n%b) + output
... n /= b
... return output
...
>>> n_as_base_b(15,2)
'1111'
>>> n_as_base_b(11,2)
'1011'

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