Python: Concatenation of two Lists behaving weird - python

I am very new to Python, and I wrote the below code which returns the kth row of a Pascal triangle where k is supplied as 'rowIndex' parameter. The problem occurs in the map function where the concatenation [0]+row is working fine but row+[0] is not working and an error is being thrown as shown below. This problem didn't occur in the code which is implemented using zip instead of map (which is commented out in the below code) Can anyone point out what the problem is?
Thanks in advance!
Error:
row = [map(lambda a, b: a + b, [0]+row, row+[0])]
TypeError: unsupported operand type(s) for +: 'int' and 'list'
Code:
class Solution(object):
def getRow(self, rowIndex):
"""
:type rowIndex: int
:rtype: List[int]
"""
row = [1]
for _ in range(rowIndex):
row = [map(lambda a, b: a + b, [0]+row, row+[0])]
# row = [x + y for x, y in zip([0]+row, row+[0])]
return row
obj = Solution()
print obj.getRow(3)

map returns a list, you should not wrap it with [...].
>>> map(lambda a, b: a + b, [0,1,2], [1,2,0]) # Python 2.x
[1, 3, 2]
By wrapping it with [..], you will get a list of a list; which will cause TypeError after the first iteration:
>>> [map(lambda a, b: a + b, [0,1,2], [1,2,0])]
[[1, 3, 2]]
row = map(lambda a, b: a + b, [0]+row, row+[0])
If you are using Python 3.x, map returns an iterator; you need to convert it to list using list function to get a list object:
>>> map(lambda a, b: a + b, [0,1,2], [1,2,0]) # Python 3.x
<map object at 0x7f5acef0a0b8>
>>> list(map(lambda a, b: a + b, [0,1,2], [1,2,0]))
[1, 3, 2]
row = list(map(lambda a, b: a + b, [0]+row, row+[0]))

Related

Unexpected TypeError when using reduce function

Here is the line of code:
product = list(reduce(lambda a, b: a*b, [2,2,2,2,2]))
Error:
TypeError: 'int' object is not iterable
if you want to put your result in a list, you can use this code:
import functools
product = [functools.reduce((lambda x,y:x*y),[2,2,2,2,2])]
print(product)
The list function cannot be used because it corresponds to a type conversion which is not possible as your result is an integer.
>>> reduce(lambda a, b: a*b, [2,2,2,2,2])
32
So you can't make a list of it.

Unpack into the list append method in Python

I run into a problem when unpacking a tuple. I want the first value to be appended to a list and a second assigned to a variable. For example:
list = []
tuple = (1, 2)
list.append, variable = tuple
But this raises an exception since I am assigning to a bultin and not actually calling in. Is that possible in Python? Or even a simpler operation such as:
a, b = 5, 4
tuple = (1, 2)
a+, b = tuple
to yield a = 6, b = 2.
There's no brief syntax to allow this. However, here's a class that creates a wrapper around a list, so that assigning to an append attribute really calls the underlying list's append method. This could be useful if you have a lot of values to append to the list.
class Appender:
def __init__(self, lst):
self.lst = lst
# The rare write-only property
append = property(None, lambda self, v: self.lst.append(v))
values = []
value_appender = Appender(values)
value_appender.append, b = (1,2)
assert values == [1]
Perhaps simpler, a subclass of list with a similar property:
class Appendable(list):
take = property(None, lambda self, v: self.append(v))
values = Appendable()
values.take, b = (1, 2)
assert values == [1]
append is a method on the builtin list type. Python allows tuple unpacking into variables in one line as a convenience, but it won't decide to call the append method with part of your tuple as an argument. Just write your code on multiple lines, that will help make it easier to read too.
my_list = []
my_tuple = (1, 2)
a, b = my_tuple
my_list.append(a)
Technically yes you could do it in a single line, but I wouldn't.
l = []
a = (1,2)
l[:0], b = [[x] if c == 0 else x for c,x in enumerate(a)]
>>> l
[1]
>>> b
2
You can use the map function on the append method for the list.
>>> a = (6,7)
>>> b = [1,2,3,4,5]
>>> list(map(b.append, a))
[None, None]
>>> b
[1, 2, 3, 4, 5, 6, 7]
I am not really sure what the list() does in this statement but it seems to work.

An error when redirecting a list of objects to reduce function with lambda

Here is the simple code.
class C:
def __init__(self):
self.l = [1,2,3]
a = C()
b = C()
c = C()
reduce(lambda x,y: x.l + y.l, [a,b,c])
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "<stdin>", line 1, in <lambda>
AttributeError: 'list' object has no attribute 'l'
I know there are several other ways. But I want to see why this doesn't work.
The output should be the same given by
sum([x.l for x in [a,b,c]], [])
which is
[1, 2, 3, 1, 2, 3, 1, 2, 3]
The function passed as the first argument to reduce takes 2 arguments, the first is the result of the previous reduction (or the first item in the iterable if no initial value is given). In your case, after the first 2 lists have been added together x is now a list when passed to the lambda for the second iteration and doesn't have an attribute l as it is not an instance of C
If you run your list through map you can extract the list from all the objects and pass them to the reduce
reduce(lambda x, y: x + y, map(lambda z: z.l, [a,b,c]))
As Iain says in his answer, the problem hits after the first term is evaluated, since your types stop matching.
Reduce is of the form: reduce(f(B,A)->B, [A], optional B) -> B
You provide a function that has a signature of f(C, C) -> [int]
reduce(lambda x,y: x.l + y.l, [a,b,c])
which doesn't match f(B,A)->B. You can clearly fix this in two ways, by changing the first argument (1) or the return (2)
(1) f(int, C) -> int. Where A is C and B is [int].
reduce(lambda x, y: x + y.l, [a, b, c], [])
(2) f(C, C) --> C. Where A is C and B is also C.
def add_c(c1, c2):
ret = C()
ret.l = c1.l + c2.l
return ret
reduce(add_c, [a, b, c]).l
Note the .l to extract your list
Note that the second is only ugly because your class is pretty silly, and has no init. Also the lowercase L as a variable is unfortunate.

Python lambda parameters

I have the following code:
g = lambda a, b, c: sum(a, b, c)
print g([4,6,7])
How do I get the lambda function to expand the list into 3 values?
Expand the list t0 3 values can be done by this:
g(*[4,6,7])
But the sum won't work in your way.
Or you can write this way:
>>> g = lambda *arg: sum(arg)
>>> print g(4, 5, 6)
15
>>>
Or just make your lambda accept a list:
g = lambda alist: sum(alist)
print g([4,6,7])
Why can't you change lambda to take a list. Because sum() doesn't take three arguments:
>>> g = lambda a_list: sum(a_list)
>>> print g([4,6,7])
17
or a non-keyword argument:
>>> g = lambda *nkwargs: sum(nkwargs)
>>> print g(4,6,7)
17
g = lambda L: sum(L)
print g([4,6,7])
would work for any arbitrarily sized list.
If you want to use g = lambda a, b, c: someFunc(a, b, c), then call print g(4,6,7)
You're defining a function which takes three parameters, and the supplying it with a single parameter, a list.
If you want
print g([4,6,7])
to work, your definition should be
g = lambda lst: sum(lst)
The code you are looking for is:
>>> g = lambda a, b, c: sum([a, b, c])
>>> print g(*[4,6,7])
17
What you were trying to do wont work:
>>> g = lambda a, b, c: sum(a, b, c)
>>> print g(*[4,6,7])
Traceback (most recent call last):
File "<pyshell#83>", line 1, in <module>
print g(*[4,6,7])
File "<pyshell#82>", line 1, in <lambda>
g = lambda a, b, c: sum(a, b, c)
TypeError: sum expected at most 2 arguments, got 3
Because sum() can't handle the arguments you gave it.
Since your lambda function is simply a sum() function, why not just call sum() directly?
If your code the following a, b, c values:
>>> a, b, c = range(1,4)
>>> print a,b,c
1 2 3
And you wanted to do:
>>> g = lambda a, b, c: sum([a, b, c])
>>> print g(*[a,b,c])
6
Why not just do the following?:
>>> sum([a,b,c])
6
>>> g=lambda *l: sum(l)
>>> print g(1,2,3)
6
If your lambda expects to have a list/tuple of fixed length passed in, but wants to expand the values in that list/tuple into separate parameter variables, the following will work.
g = lambda (a, b, c): a + b + c
g([4, 6, 7])
Note the parentheses around the parameter list.
This "feature" works in Python 2.x, but was removed in Python 3

Python : Map function with none type list as parameter

I want to pass a list of None in a map function but it doesn't work.
a = ['azerty','uiop']
b = ['qsdfg','hjklm']
c = ['wxc','vbn']
d = None
def func1(*y):
print 'y:',y
map((lambda *x: func1(*x)), a,b,c,d)
I have this message error:
TypeError: argument 5 to map() must support iteration.
Replace None with an empty list:
map(func1, a or [], b or [], c or [], d or [])
or filter the lists:
map(func1, *filter(None, (a, b, c, d)))
The filter() call removes d from the list altogether, while the first option gives you None values to your function call.
I removed the lambda, it is redundant here.
With the or [] option, the 4th argument is None:
>>> map(func1, a or [], b or [], c or [], d or [])
y: ('azerty', 'qsdfg', 'wxc', None)
y: ('uiop', 'hjklm', 'vbn', None)
[None, None]
Filtering results in 3 arguments to func1:
>>> map(func1, *filter(None, (a, b, c, d)))
y: ('azerty', 'qsdfg', 'wxc')
y: ('uiop', 'hjklm', 'vbn')
[None, None]
You could use itertools.starmap() as well, but that gets a little verbose:
>>> list(starmap(func1, zip(*filter(None, (a, b, c, d)))))
y: ('azerty', 'qsdfg', 'wxc')
y: ('uiop', 'hjklm', 'vbn')
[None, None]
Make 2nd argument to map a list or tuple:
map((lambda *x): func1(*x)), (a,b,c,d))
The error message pretty much says it all: None is not iterable. Arguments to map should be iterable:
map(func, *iterables) --> map object
Make an iterator that computes the function using arguments from
each of the iterables. Stops when the shortest iterable is exhausted.
Depending on what you want to achieve, you can:
change None to an empty list;
map your function on a list of [a, b, c, d]
Also note that you can map func1 directly, without a lambda:
map(func1, *iterables)
2nd argument d should be a SEQUENCE , make it as a list or tuple..

Categories