Pass array to function and loop over values by index - python

I keep getting a TypeError: unsupported operand type for +: 'int' and 'list'
so I guess the array isn't being indexed? Please assist.
def main():
arr = [1, 2, 3, 4, 5]
length = len(arr)
maxAns = msa2(length, arr)
print maxAns
def msa2(length, *arr):
maxThus = 0
for i in range(0, length):
sum = 0
for j in range(i, length):
sum = sum + arr[j] # how to get value in index j
max(maxThus, sum)
return maxThus
if __name__ == '__main__':
main()

You should not use *arr; remove the * wildcard character and your code will work.
With the wildcard character, the argument passed into msa2 is seen as one of potentially more extra positional arguments, so arr inside msa2 is a list of those arguments, with the first element being the list you passed in when you called msa2:
>>> def foo(*args):
... print args
...
>>> foo(1, 2, 3)
(1, 2, 3)
>>> foo([1, 2, 3])
([1, 2, 3],)
Your function also will always return 0; you do not update maxThus anywhere. You probably meant to assign the result of max(maxThus, sum) to maxThus:
maxThus = max(maxThus, sum)

Related

How can I get rid of yield and use another function instead in my code

def mot (n) :
if n==0 :
yield n
else :
for m in mot(n-1) :
yield [m]
for k in range(0,n-1) :
for l in mot(k) :
for r in mot(n-2-k) :
yield (l,r)
def countFor(f,n) :
for i in range(n) :
count = 0
for t in f(i) :
count+=1
yield count
def countsFor(mes,f,n) :
print(mes)
print([c for c in countFor(f,n)])
print("")
def showFor(mes,f,n) :
print(mes)
for t in f(n) :
print(t)
print("")
showFor('Motzkin trees',mot,4)
countsFor('Motzkin trees',mot,12)
print("done")
def test() :
for n in range(6) :
print(n,list(mot(n)))
I have the following code that outputs the motzkin numbers, I want to change the yield expressions to another, more simple expressions or functions, how can I do that , what can I do?
thanks
Getting rid of yield from a generator function that generates a finite sequence is as easy as appending the yielded values to a list for return instead.
For example, your mot function can be revised without yield as:
def mot(n) :
output = []
if n==0 :
output.append(n)
else :
for m in mot(n-1) :
output.append([m])
for k in range(0,n-1) :
for l in mot(k) :
for r in mot(n-2-k) :
output.append((l,r))
return output
But unless the caller needs to perform index-based operations with the returning list, there's no need to convert the function so it returns a list, as generators are both faster and more memory-efficient.
According to wikipedia, the Moptzkin numbers satisfy this recurrence relation:
M_n = ((2n + 1)/(n + 2)) M_(n-1) + ((3n - 3)/(n+2)) M_(n-2)
That's easy enough to translate into code:
from itertools import count
def mot():
M_n1 = 1
M_n2 = 1
yield 1
yield 1
for n in count(2):
M = ((2*n + 1)/(n + 2))*M_n1 + ((3*n - 3)/(n+2))*M_n2
M = int(M)
yield M
M_n1, M_n2 = M, M_n1
Now we can loop through the terms of the sequence until the numbers get too big for memory, or just slice a few from the front of the list:
from itertools import islice
print(list(islice(mot(), 10)))
# [1, 1, 2, 4, 9, 21, 51, 127, 323, 835]
As a bit of dynamic programming:
def mot(t):
M = [1, 1]
for n in range(2, t+1):
M.append(((2*n + 1)*M[n-1] + (3*n - 3)*M[n-2]) // (n + 2))
return M
In []:
mot(4)
Out[]:
[1, 1, 2, 4, 9]
In []:
mot(10)
Out[]:
[1, 1, 2, 4, 9, 21, 51, 127, 323, 835, 2188]

Inheriting list: Creating division by other lists, integers and floats

I wanted to be able to divide entire lists by integers, floats, and other lists of equal length in Python, so I wrote the following little script.
class divlist(list):
def __init__(self, *args, **kwrgs):
super(divlist, self).__init__(*args, **kwrgs)
self.__cont_ = args[0]
self.__len_ = len(args[0])
def __floordiv__(self, other):
""" Adds the ability to floor divide list's indices """
if (isinstance(other, int) or isinstance(other, float)):
return [self.__cont_[i] // other \
for i in xrange(self.__len_)]
elif (isinstance(other, list)):
return [self.__cont_[i] // other[i] \
for i in xrange(self.__len_)]
else:
raise ValueError('Must divide by list, int or float')
My question: How can I write this in a simpler way? Do I really need the lines self.__cont_ and self.__len_? I was looking through the list's 'magic' methods and I couldn't find one that readily held this information.
An example of calling this simple class:
>>> X = divlist([1,2,3,4])
[1, 2, 3, 4]
>>> X // 2
[0, 1, 1, 2]
>>> X // [1,2,3,4]
[1, 1, 1, 1]
>>> X // X
[1, 1, 1, 1]
How can I write this in a simpler way?
By using self[i] instead of self.__cont_[i].
Do I really need the lines self.__cont_ and self.__len_?
No. Just use the regular methods of referring to a list, for example: [] and len().
As an aside, you might choose to have .__floordiv__() return a divlist instead of a list, so that you can continue to operate on the result.
class divlist(list):
def __floordiv__(self, other):
""" Adds the ability to floor divide list's indices """
if (isinstance(other, int) or isinstance(other, float)):
return [i // other for i in self]
elif (isinstance(other, list)):
# DANGER: data loss if len(other) != len(self) !!
return [i // j for i,j in zip(self, other)]
else:
raise ValueError('Must divide by list, int or float')
X = divlist([1,2,3,4])
assert X == [1, 2, 3, 4]
assert X // 2 == [0, 1, 1, 2]
assert X // [1,2,3,4] == [1, 1, 1, 1]
assert X // X == [1, 1, 1, 1]
Instead of examining the explicit types of each argument, assume that either the second argument is iterable, or it is a suitable value as the denominator for //.
def __floordiv__(self, other):
try:
pairs = zip(self, other)
except TypeError:
pairs = ((x, other) for x in self)
return [x // y for (x, y) in pairs]
You may want to check that self and other have the same length if the zip succeeds.

python - enter the correct number of variables based on function handle

I have a list of variables, and a function object and I would like to assign the correct number of variable depending on the function.
def sum2(x,y):
return x + y
def sum3(x,y,z):
return x + y + z
varList = [1,2,3]
so if f = sum2 , I would like it to call first 2 elements of varList, and if f = sum3 , to call it with 3 elements of the function.
This can be done in a single function, if you are always returning the sum of all the passed arguments.
def sum1(*args):
return sum(args)
This is just utilizing positional arguments, as you don't appear to need to explicitly set individual values. It is also most flexible than the solution provided by ZdaR, as you don't need to know ahead of time the maximum number of arguments you can receive.
Some examples:
>>> print sum1(1, 2, 3)
6
>>> print sum1(1)
1
>>> print sum1(-1, 0, 6, 10)
15
Use the inspect module as follows:
import inspect
n2 = len(inspect.getargspec(sum2)[0])
n3 = len(inspect.getargspec(sum3)[0])
sum2(*varList[0:n2])
sum3(*varList[0:n3])
getargspec returns a 4-tuple of (args, varargs, keywords, defaults). So the above code works if all your args are explicit, i.e. not * or ** args. If you have some of those, change the code accordingly.
You may use default initialization, You should keep in mind the maximum number of variables that could be passed to this function. Then create a function with that number of parameters but initializing them with 0, because a+0 = a(in case some parameters are missing it will replace then with 0 which won't affect the results.)
def sum1(a=0, b=0, c=0, d=0):
return a+b+c+d
print sum1(1)
>>> 1
print sum1(1, 2)
>>> 3
print sum1(1, 2, 3)
>>> 6
print sum1(1, 2, 3, 4)
>>> 10
However, if you call the function with more than 4 arguments, it would raise error statement
Also as suggested by #CoryKramer in the comments you can also pass your varlist = [1, 2, 3, 4] as a parameter :
print sum1(*varlist)
>>> 10
Keeping in mind that the len(varlist) should be less than the number of parameters defined.
A general solution:
To get the number of argument, you can use f.func_code.co_argcount and than pass the correct elements from the list:
def sum2(x,y):
return x + y
def sum3(x,y,z):
return x + y + z
varlist = [2,5,4]
[f(*varlist[:f.func_code.co_argcount]) for f in [sum2,sum3]]
>> [7, 11]
You can check if f is a function with the is keyword
def sum2(x, y):
return x + y
def sum3(x, y, z):
return x + y + z
varList = [1, 2, 3]
f = sum2
if f is sum2:
sum = f(varList[0], varList[1])
print('Sum 2: ' + str(sum))
# Prints: 'Sum 2: 3'
f = sum3
if f is sum3:
sum = f(varList[0], varList[1], varList[2])
print('Sum 3: ' + str(sum))
# Prints: 'Sum 3: 6'
A dict of functions:
def two(l):
return l[0] + l[1]
def three(l):
return l[0] * l[1] + l[2]
funcs = {2:two, 3:three}
l = [1, 2, 3]
print len(l)
print funcs[len(l)](l)

Basics of recursion in Python

"Write a recursive function, "listSum" that takes a list of integers and returns the sum of all integers in the list".
Example:
>>> listSum([1, 3, 4, 5, 6])
19
I know how to do this another way but not in the recursive way.
def listSum(ls):
i = 0
s = 0
while i < len(ls):
s = s + ls[i]
i = i + 1
print(s)
I need the basic way to do this since special built-in functions is not allowed.
Whenever you face a problem like this, try to express the result of the function with the same function.
In your case, you can get the result by adding the first number with the result of calling the same function with rest of the elements in the list.
For example,
listSum([1, 3, 4, 5, 6]) = 1 + listSum([3, 4, 5, 6])
= 1 + (3 + listSum([4, 5, 6]))
= 1 + (3 + (4 + listSum([5, 6])))
= 1 + (3 + (4 + (5 + listSum([6]))))
= 1 + (3 + (4 + (5 + (6 + listSum([])))))
Now, what should be the result of listSum([])? It should be 0. That is called base condition of your recursion. When the base condition is met, the recursion will come to an end. Now, lets try to implement it.
The main thing here is, splitting the list. You can use slicing to do that.
Simple version
>>> def listSum(ls):
... # Base condition
... if not ls:
... return 0
...
... # First element + result of calling `listsum` with rest of the elements
... return ls[0] + listSum(ls[1:])
>>>
>>> listSum([1, 3, 4, 5, 6])
19
Tail Call Recursion
Once you understand how the above recursion works, you can try to make it a little bit better. Now, to find the actual result, we are depending on the value of the previous function also. The return statement cannot immediately return the value till the recursive call returns a result. We can avoid this by, passing the current to the function parameter, like this
>>> def listSum(ls, result):
... if not ls:
... return result
... return listSum(ls[1:], result + ls[0])
...
>>> listSum([1, 3, 4, 5, 6], 0)
19
Here, we pass what the initial value of the sum to be in the parameters, which is zero in listSum([1, 3, 4, 5, 6], 0). Then, when the base condition is met, we are actually accumulating the sum in the result parameter, so we return it. Now, the last return statement has listSum(ls[1:], result + ls[0]), where we add the first element to the current result and pass it again to the recursive call.
This might be a good time to understand Tail Call. It would not be relevant to Python, as it doesn't do Tail call optimization.
Passing around index version
Now, you might think that we are creating so many intermediate lists. Can I avoid that?
Of course, you can. You just need the index of the item to be processed next. But now, the base condition will be different. Since we are going to be passing index, how will we determine how the entire list has been processed? Well, if the index equals to the length of the list, then we have processed all the elements in it.
>>> def listSum(ls, index, result):
... # Base condition
... if index == len(ls):
... return result
...
... # Call with next index and add the current element to result
... return listSum(ls, index + 1, result + ls[index])
...
>>> listSum([1, 3, 4, 5, 6], 0, 0)
19
Inner function version
If you look at the function definition now, you are passing three parameters to it. Lets say you are going to release this function as an API. Will it be convenient for the users to pass three values, when they actually find the sum of a list?
Nope. What can we do about it? We can create another function, which is local to the actual listSum function and we can pass all the implementation related parameters to it, like this
>>> def listSum(ls):
...
... def recursion(index, result):
... if index == len(ls):
... return result
... return recursion(index + 1, result + ls[index])
...
... return recursion(0, 0)
...
>>> listSum([1, 3, 4, 5, 6])
19
Now, when the listSum is called, it just returns the return value of recursion inner function, which accepts the index and the result parameters. Now we are only passing those values, not the users of listSum. They just have to pass the list to be processed.
In this case, if you observe the parameters, we are not passing ls to recursion but we are using it inside it. ls is accessible inside recursion because of the closure property.
Default parameters version
Now, if you want to keep it simple, without creating an inner function, you can make use of the default parameters, like this
>>> def listSum(ls, index=0, result=0):
... # Base condition
... if index == len(ls):
... return result
...
... # Call with next index and add the current element to result
... return listSum(ls, index + 1, result + ls[index])
...
>>> listSum([1, 3, 4, 5, 6])
19
Now, if the caller doesn't explicitly pass any value, then 0 will be assigned to both index and result.
Recursive Power problem
Now, lets apply the ideas to a different problem. For example, lets try to implement the power(base, exponent) function. It would return the value of base raised to the power exponent.
power(2, 5) = 32
power(5, 2) = 25
power(3, 4) = 81
Now, how can we do this recursively? Let us try to understand how those results are achieved.
power(2, 5) = 2 * 2 * 2 * 2 * 2 = 32
power(5, 2) = 5 * 5 = 25
power(3, 4) = 3 * 3 * 3 * 3 = 81
Hmmm, so we get the idea. The base multiplied to itself, exponent times gives the result. Okay, how do we approach it. Lets try to define the solution with the same function.
power(2, 5) = 2 * power(2, 4)
= 2 * (2 * power(2, 3))
= 2 * (2 * (2 * power(2, 2)))
= 2 * (2 * (2 * (2 * power(2, 1))))
What should be the result if anything raised to power 1? Result will be the same number, right? We got our base condition for our recursion :-)
= 2 * (2 * (2 * (2 * 2)))
= 2 * (2 * (2 * 4))
= 2 * (2 * 8)
= 2 * 16
= 32
Alright, lets implement it.
>>> def power(base, exponent):
... # Base condition, if `exponent` is lesser than or equal to 1, return `base`
... if exponent <= 1:
... return base
...
... return base * power(base, exponent - 1)
...
>>> power(2, 5)
32
>>> power(5, 2)
25
>>> power(3, 4)
81
Okay, how will be define the Tail call optimized version of it? Lets pass the current result as the parameter to the function itself and return the result when the base condition it met. Let's keep it simple and use the default parameter approach directly.
>>> def power(base, exponent, result=1):
... # Since we start with `1`, base condition would be exponent reaching 0
... if exponent <= 0:
... return result
...
... return power(base, exponent - 1, result * base)
...
>>> power(2, 5)
32
>>> power(5, 2)
25
>>> power(3, 4)
81
Now, we reduce the exponent value in every recursive call and multiple result with base and pass it to the recursive power call. We start with the value 1, because we are approaching the problem in reverse. The recursion will happen like this
power(2, 5, 1) = power(2, 4, 1 * 2)
= power(2, 4, 2)
= power(2, 3, 2 * 2)
= power(2, 3, 4)
= power(2, 2, 4 * 2)
= power(2, 2, 8)
= power(2, 1, 8 * 2)
= power(2, 1, 16)
= power(2, 0, 16 * 2)
= power(2, 0, 32)
Since exponent becomes zero, the base condition is met and the result will be returned, so we get 32 :-)
Early exit is typical for recursive functions. seq is falsy when empty (therefore when there are no numbers left to sum).
Slice syntax allows to pass sequence to recursively called function without integer consumed in current step.
def listSum(seq):
if not seq:
return 0
return seq[0] + listSum(seq[1:])
print listSum([1,3,4,5,6]) # prints 19
def listSum(L):
"""Returns a sum of integers for a list containing
integers.
input: list of integers
output: listSum returns a sum of all the integers
in L.
"""
if L == []:
return []
if len(L) == 1:
return L[0]
else:
return L[0] + listSum(L[1:])
print listSum([1, 3, 4, 5, 6])
print listSum([])
print listSum([8])
Another version:
def listSum(ls):
ls_len = len(ls)
# Base condition
if ls_len==1:
return ls[0]
if ls_len==0:
return None
# ls = listSum(ls[0:i]) + listSum(ls[i:])
elif ls_len%2==0:
i = int(ls_len/2)
return listSum(ls[0:i]) + listSum(ls[i:])
else:
i = int((ls_len-1)/2)
return listSum(ls[0:i]) + listSum(ls[i:])
Follow #thefourtheye's example, we can say:
listSum([1, 3, 4, 5, 6]) = listSum([1, 3]) + listSum([4, 5, 6])
= (listSum([1]) + listSum([3])) + (listSum([4]) + listSum([5, 6]))
= (listSum([1]) + listSum([3])) + (listSum([4]) + (listSum([5]) + listSum([6])))
Base condition: when ls only has one element, return this value.
def listsum(list):
if len(list) == 1:
return list[0]
else:
return list[0] + listsum(list[1:])
print(listsum([1,5,9,10,20]))
The basic idea behind this recursive function is that we want to check if we have a base case which is shown as if len(list) == 1:. For the base case we just return the value in the list return list[0], otherwise, we still have multiple elements in the list. In the else: statement we will add the first element from the list which is list[0] to the rest of the elements in the list.This is shown by calling the function recursively with the list shorter by 1 element--the element at index 0-- listsum(list[1:]), this process repeats with the list getting smaller until you arrive at the base case--a list of length 1 and then you will get a final result.

Transposition Cipher errors python

I'm trying to write a function encr(k,m) where the message m is any string over the characters A...Za...z and where the key k is a permutation. When len(m) isn't a multiple of len(k), then I need to append Z's to m to make len(m) a multiple of len(k).
So far I've got
import math, pyperclip
def encr(k, m):
ciphertext = [''] * k
for col in range(len(k)):
pointer = col
while pointer < len(m):
ciphertext[col] += m[pointer]
pointer += 1
return ''.join(ciphertext)
I keep getting an error: TypeError: can't multiply sequence by non-int of type 'list' on line 3, in encr ciphertext = [''] * k
Any help would be great
An example of input would be encr([3, 2, 4, 1, 0], 'SineLaboreNihil')
You current error is that k is a string in your function, and you are attempting to add that to an integer - pointer. I think you meant to add 1 to pointer.
You are also attempting to take range() on that same string. range(len(k)) is what you need to do.
Your new error can be corrected as follows -
ciphertext = [''] * len(k)

Categories

Resources