I am new to Python and practicing basics. I am using a lambda expression to take two arguments and performing square operations on them (eg: var ** 2). The two arguments are coming from the zip(list1, list2). I am getting TypeError for this. I tried searching for the solution but didn't get any. I even tried writing lambda arguments in parenthesis (eg: lambda (v1,v2):) but that threw SyntaxError.
Below is the python code:
list1 = [1,2,3,4]
list2 = [5,6,7,8]
print ( list(map(lambda v1,v2: (v1**2, v2**2), list(zip(list1, list2)))) )
Error:
TypeError Traceback (most recent call last)
<ipython-input-241-e93d37efc752> in <module>()
1 list1 = [1,2,3,4]
2 list2 = [5,6,7,8]
----> 3 print ( list(map(lambda v1,v2: (v1**2, v2**2), list(zip(list1, list2)))) )
TypeError: <lambda>() missing 1 required positional argument: 'v2'
You're giving a single list as argument to map, thus map calls your lambda with one element of the list at a time - that is one argument, even though it is a tuple. What you probably want is:
print ( list(map(lambda v: (v[0]**2, v[1]**2), zip(list1, list2))) )
so that your item from the list is passed as a sole argument to lambda.
If you insist on the two-argument lambda, discard zip and pass your lists directly to map as separate arguments:
print ( list(map(lambda v1,v2: (v1**2, v2**2), list1, list2)) )
In your print, map will cal the function lambda on a list of tuples (as list(zip(list1, list2)) produce a list of tuples).
So for instance you can do :
print(list(map(lambda(v1,v2): (v1**2, v2**2), list(zip(list1, list2)))))
Your lambda function will use the tuple (v1,v2) as parameters, instead of two parameters.
Related
I know a map function gets a function as its first argument and the next arguments are iterators on which the passed function needs to be applied. My question here is say if I have a 2d list like so
l=[[1,2,3],[4,5,6],[7,8,9]]
how can I sort the individual lists in reverse order so my output is
l=[[3,2,1],[6,5,4],[9,8,7]]
I know a potential solution is using a lambda function such as
list(map(lambda x:x[::-1],l))
I want something like this
list(map(sorted, l,'reversed=True'))
where 'reversed=True' is an argument that sorted takes
eg:
>>> newList=[1,2,3]
>>> sorted(newList,reversed='True')
>>> [3,2,1]
I have seen how to pass arguments to a the pow function using the itertools.repeat module
map(pow,list,itertools.repeat(x))
x=power to which the list must be raised
I want to know if there is any way the arguments can be passed in a map function. In my case the 'reverse=True' for the sorted function.
You can use functools.partial for this:
import functools
new_list = list(map(functools.partial(sorted, reverse=True), l))
You can use a lambda to wrap the funtion:
map(lambda x: sorted(x, reversed=True), l)
or:
map(lambda i, j: pow(i, j), list,itertools.repeat(x))
There are many ways to do it.
You could use functools.partial. It creates a partial, for the lack of a better word, of the function you pass to it. It sort of creates a new function with some parameters already passed into it.
For your example, it would be:
from functools import partial
rev_sort = partial(sorted, reverse=True)
map(rev_sort, l)
The other way is using a simple lambda:
map(lambda arr: sorted(arr, reverse=True), l)
The other other way (my personal choice), is using generators:
(sorted(arr, reverse=True) for arr in l)
For this specific case, you can also use a list comprehension -
l=[[1,2,3],[4,5,6],[7,8,9]]
l = [list(reversed(sublist)) for sublist in l]
//[[3,2,1],[6,5,4],[9,8,7]]
Example:
def somerando(a,b,c,d):
if not a+b+c+d == 9000:
return (a+b+c+d)
somerando(1,2,3,4)
Returns: 10
but
randonumbs = [1,2,3,4]
somerando(randonumbs)
Gives the following error:
TypeError Traceback (most recent call
last) in
----> 1 somerando(randonumbs)
TypeError: somerando() missing 3 required positional arguments: 'b',
'c', and 'd'
your function expects 4 arguments. randonumbs = [1,2,3,4] is a list (of four items); that is one argument for your function.
you could do this:
randonumbs = [1,2,3,4]
somerando(*randonumbs)
this usage of the asterisk (*) is discussed in this question or in PEP 3132.
You passed randonumbs as list, means this whole list is considered as first argument to the function somerando
You can use somerando(*randonumbs) .
Here, * means pass as tuple & ** means pass as dictionary (key, value pair) if you use ** in function parameters/ arguments.
Thank you.
The single-asterisk form of *args can be used as a parameter to send a non-keyworded variable-length argument list to functions, like below
randonumbs = [1,2,3,4]
somerando(*randonumbs)
The double asterisk form of **kwargs is used to pass a keyworded, variable-length argument dictionary to a function.
randonumbs = {'a':1, 'b':2, 'c': 3, 'd': 4}
somerando(**randonumbs)
So I'm trying to do this.
a = []
map(lambda x: a.append(x),(i for i in range(1,5)))
I know map takes a function but so why doesn't it append to the list? Or is append not a function?
However printing a results to a still being empty
now an interesting thing is this works
a = []
[a.append(i) for i in range(5)]
print(a)
aren't they basically "saying" the same thing?
It's almost as if that list comprehension became some sort of hybrid list-comprehension function thing
So why doesn't the lambda and map approach work?
I am assuming you are using Python 3.x , the actual reason why your code with map() does not work is because in Python 3.x , map() returns a generator object , unless you iterate over the generator object returned by map() , the lambda function is not called . Try doing list(map(...)) , and you should see a getting filled.
That being said , what you are doing does not make much sense , you can just use -
a = list(range(5))
append() returns None so it doesn't make sense using that in conjunction with map function. A simple for loop would suffice:
a = []
for i in range(5):
a.append(i)
print a
Alternatively if you want to use list comprehensions / map function;
a = range(5) # Python 2.x
a = list(range(5)) # Python 3.x
a = [i for i in range(5)]
a = map(lambda i: i, range(5)) # Python 2.x
a = list(map(lambda i: i, range(5))) # Python 3.x
[a.append(i) for i in range(5)]
The above code does the appending too, however it also creates a list of None values as the size of range(5) which is totally a waste of memory.
>>> a = []
>>> b = [a.append(i) for i in range(5)]
>>> print a
[0, 1, 2, 3, 4]
>>> print b
[None, None, None, None, None]
The functions map and filter have as first argument a function reference that is called for each element in the sequence (list, tuple, etc.) provided as second argument AND the result of this call is used to create the resulting list
The function reduce has as first argument a function reference that is called for first 2 elems in the sequence provided as second argument AND the result is used together with the third elem in another call, then the result is used with the fourth elem, and so on. A single value results in the end.
>>> map(lambda e: e+10, [i for i in range(5)])
[10, 11, 12, 13, 14]
>>> filter(lambda e: e%2, [i for i in range(5)])
[1, 3]
>>> reduce(lambda e1, e2: e1+e2, [i for i in range(5)])
10
Explanations:
map example: adds 10 to each elem of list [0,1,2,3,4]
filter example: keeps only elems that are odd of list [0,1,2,3,4]
reduce example: add first 2 elems of list [0,1,2,3,4], then the result and the third elem of list, then the result and fourth elem, and so on.
This map doesn't work because the append() method returns None and not a list:
>>> a = []
>>> type(a.append(1))
<class 'NoneType'>
To keep it functional why not use reduce instead?
>>> from functools import reduce
>>> reduce(lambda p, x: p+[x], (i for i in range(5)), [])
[0, 1, 2, 3, 4]
Lambda function will not get triggered unless you wrap the call to map function in list() like below
list(map(lambda x: a.append(x),(i for i in range(1,5))))
map only returns a generator object which needs to be iterated in order to create a list. Above code will get the lambda called.
However this code does not make much sense considering what you are trying to achieve
I could not find such a question in the archive.
With for is possible to unpack iterated pairs:
>>> for i, x in enumerate([5,10,15]): print('x[%d]=%d' % (i, x))
x[0]=5
x[1]=10
x[2]=15
or also is possible to not unpack them:
>>> for x in enumerate([5,10,15]): print(x)
(0, 5)
(1, 10)
(2, 15)
However, when using map(), this unpack is not possible:
>>> list(map(lambda i, x: x**i, enumerate([5,10,15])))
Traceback (most recent call last):
File "<input>", line 1, in <module>
TypeError: <lambda>() missing 1 required positional argument: 'x'
Why is this? Design choice? And why?
I guess one could implement such a wrapper:
def map1(func, *iterables):
from inspect import signature
params = signature(func).parameters
if len(params) == 1:
yield from map(func, *iterables)
else:
yield from map(lambda x: func(*x), *iterables)
(works in every case)
or this other one, that blindly unpacks arguments:
def map2(func, *iterables):
yield from map(lambda x: func(*x), *iterables)
(I guess the latter is going to cause some trouble)
Is there a (good) reason to not do it?
This is not an issue with lambda but with map. The documentation says:
If additional iterable arguments are passed, function must take that many arguments and is applied to the items from all iterables in parallel.
In other words, the function must take the same number of arguments as the number of iterables that you pass. The size of each individual element in the iterables is not relevant.
If you want to pass each element of a single iterable as multiple arguments, you can use zip and argument unpacking to transpose the sequence:
>>> map(lambda i, x: x**i, *zip(*enumerate([5,10,15])))
[1, 10, 225]
As Ashwini noted, you can also use itertools.starmap instead of map.
This is because enumerate() returns a single enumerate object which holds pair of values in multiple enumerate objects. If you try:
>>> enumerate([5,10,15])
>>> <enumerate at 0x39152d8>
>>>e = enumerate([5,10,15])
>>> for i in e:
print e
<enumerate object at 0x03915080>
<enumerate object at 0x03915080>
<enumerate object at 0x03915080>
What you are doing int his statement:
map(lambda i, x: x**i, enumerate([5,10,15]))
is passing return value of enumerate() to lambda. So it gets only one value while you specified two arguments.
If you try:
>>>map(lambda i: i[0] * i[1], enumerate([5,10,15]))
>>> [0,10,30]
you get expected output
I have some code as shown below.
import math
square_root = lambda x: math.sqrt(x)
list = [1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16]
map(square_root,list)
Output:
[1.0,
1.4142135623730951,
1.7320508075688772,
2.0,
2.23606797749979,
2.449489742783178,
2.6457513110645907,
2.8284271247461903,
3.0,
3.1622776601683795,
3.3166247903554,
3.4641016151377544,
3.605551275463989,
3.7416573867739413,
3.872983346207417,
4.0]
Now I want to use power instead of square_root
import math
power = lambda x: math.power(x,n)
list = [1,2,3,4,5]
map(power,list,2)
And I get the following error? How do I use two arguments with map?
TypeError Traceback (most recent call last)
/home/AD/karthik.sharma/ws_karthik/trunk/ in ()
----> 1 map(power,list,2)
TypeError: argument 3 to map() must support iteration
One way to do this is the following:
power = lambda x, n: math.pow(x,n)
list = [1,2,3,4,5]
map(power,list,[2]*len(list))
The expression [2]*len(list) creates another list the same length as your existing one, where each element contains the value 2. The map function takes an element from each of its input lists and applies that to your power function.
Another way is:
power = lambda x, n: math.pow(x,n)
list = [1,2,3,4,5]
map(lambda x: power(x, 2),list)
which uses partial application to create a second lambda function that takes only one argument and raises it to the power 2.
Note that you should avoid using the name list as a variable because it is the name of the built-in Python list type.
Like this:
power = lambda x, n: math.pow(x,n)
list = [1,2,3,4,5]
map(lambda x: power(x, 2), list)
List comprehensions are another option:
list = [1,2,3,4,5]
[math.pow(x,2) for x in list]
import math
power = lambda n: lambda x: math.pow(x,n)
list = [1,2,3,4,5]
map(power(2),list)