If I have a list containing a lambda function, for example:
a = [lambda x: x * 2]
how could I call this lambda function to a list:
b = [1,2,3,4]
so that it could have the result as:
result = list(map(lambda x: x * 2, b))
and get:
[2,4,6,8]
Further, what if a contains two lambda functions, for example:
a = [lambda x:x * 2, lambda x: x-1]
How could I call these functions to list b without using for loop or list comprehension but use map()?
I hope someone could help me with it!
You can simply do
result = list(map(a[0], b))
# [2,4,6,8]
since the lambda function is the first element of a
For the second function it's the same thing
result = list(map(a[1], b))
If you want to apply all functions in one line
[list(map(a[i],b)) for i in range(len(a))]
#[[2, 4, 6, 8], [0, 1, 2, 3]]
You can iterate over the lambda functions in the list no matter how many elements stored in it:
a = [lambda x:x * 2, lambda x: x-1]
b = [1, 2, 3, 4]
for func in a:
# apply each function on b and turn the results to list:
print(list(map(func, b)))
If you want to store each result:
a = [lambda x:x * 2, lambda x: x-1]
b = [1, 2, 3, 4]
results = []
for func in a:
results.append(list(map(func, b)))
In the special case of a single lambda wrapped in a list, do
result = list(map(a[0], b))
But there are no special cases in python. So for the general case, you can either have a flat list:
result = [f(x) for f in a for x in b]
or a nested one:
result = [[f(x) for f in a] for x in b]
You can reverse the sort order of the lists by swapping the loops over a and b.
You can even go as far as using itertools.product to get the flat case (again with a and b interchangeable to change the order of the result):
result = [f(x) for f, x in itertools.product(a, b)]
Related
I have the following code snippet but it is giving me the type error above. What I basically wanted to do is add two to every element and reduct it to a single sum, but it didnt work. How can we achieve this??
import functools
list1 = [1,2,3,4]
result = functools.reduce(lambda x:x+2, list1)
print(result)
Update:
It works when I do the following though:
list1 = [1,2,3,4]
result = functools.reduce(lambda x,y:x+y, list1)
print(result)
reduce() requires a lambda function which takes 2 arguments.
The first argument is the collector.
But here, so that +2 is applied also on the first argument, you have to give the initial value 0.
import functools
list1 = [1,2,3,4]
result = functools.reduce(lambda acc, el: acc + el + 2, list1, 0)
print(result) ## sum([3, 4, 5, 6]) = 18
You basically want to do a normal summing reduce(lambda x, y: x + y, lst) => sum(lst)
and a map(lambda x: x + 2, l) which is expressed in a more pythonic way as a list comprehension:
l = [1, 2, 3, 4]
sum([x + 2 for x in l]) # most pythonic!
## 18
sum(map(lambda x: x + 2, l))
## 18
or:
import functools
l = [1, 2, 3 ,4]
result = functools.reduce(lambda x, y: x + y, [x + 2 for x in l])
result ## 18
or:
import functools
l = [1, 2, 3 ,4]
result = functools.reduce(lambda x, y: x + y, map(lambda x: x + 2, l))
result ## 18
The callable passed to the reduce function needs to take two arguments to aggregate the current result with the next item from the given iterable:
import functools
list1 = [1, 2, 3, 4]
result = functools.reduce(lambda x, y: x + y + 2, list1, 0)
print(result)
This outputs:
18
I'm having trouble with this lambdas syntax.
I'm trying to translate a list of booleans to an integer value, but I'm getting an error, I don't understand why.
Here is the code:
from functools import reduce
binary = [True, True, False, True]
L = list(range(len(binary))) #Step 1
print(L) #[0, 1, 2, 3]
L = map(lambda a: 2**a, L) #Step 2
print(L) #[1, 2, 4, 8]
L = zip(binary, L) #Step 3
print(L) #[(True, 1),(True, 2),(False, 4),(True, 8)]
L = filter(lambda a, b: a, L) #Step 4
print(L) #[(True, 1),(True, 2),(True, 8)] not sure
L = map(lambda a, b: b, L) #Step 5
print(L) #?????
L = reduce(lambda a, b: a + b, L) #Final step
print(L) #11
Output:
Traceback (most recent call last):
File "C:/Users/axel_/PycharmProjects/Python_Subject_Exam/19_new_exam_binary_list_translation.py", line 27, in <module>
L = reduce(lambda a, b: a + b, L)
TypeError: <lambda>() missing 1 required positional argument: 'b'
[0, 1, 2, 3]
<map object at 0x00000267FAFE5388>
<zip object at 0x00000267FAFE50C8>
<filter object at 0x00000267FAFE5248>
<map object at 0x00000267FAFE4EC8>
Process finished with exit code 1
Could anyone help me to debug?
I think this will solve your problem. I will write some comments in the code to help you understand:
from functools import reduce
binary = [True, True, False, True]
L = list(range(len(binary))) #[0, 1, 2, 3]
L = map(lambda a: 2**a, L) #[1, 2, 4, 8]
L = zip(binary, L) #[(True, 1), (True, 2), (False, 4), (True, 8)]
L = filter(lambda x: x[0], L) #<--- an item from zip() is an ((unpacked)) tuple
L = map(lambda x: x[1], L)
L = reduce(lambda a, b: a + b, L)
print(L) #11
This is one of the challenges if you are new to using iterators.
The iterator is evaluated as each item is pulled off the iterator, this means that when you call reduce to combine the result all of the lambda expressions are evaluated at that time. In your example this is equivalent to the following expression:
L = list(range(len(binary)))
L = reduce(lambda a, b: a + b,
map(lambda a, b: b,
filter(lambda a, b: a,
zip(binary,
map(lambda a: 2**a, L)
)
)
)
)
print(L)
Confusing?
In your example the line L = filter(lambda a, b: a, L) #Step 4 has an error. A filter expression takes a callable expression that takes a single argument along with an iterable but because it is not evaluated to the end you receive a confusing error.
One approach (and a good one when debugging) is to wrap each step in a call to list to force the evaluation to occur on each line eg L = list(filter(lambda a, b: a, L)). This will make the location of the error more apparent.
Alternatively use a generator expression rather than filter/map eg:
# filter (return odd numbers between 1 and 10)
result_a = filter(lambda a: a % 2, range(1, 11))
result b = (a for a in range(1, 11) if a % 2)
# map (return powers of 2)
result_a = map(lambda a: 2**a, range(11))
result_b = (2**a for a in range(11))
All of the results are the same but generator expressions have another trick, you can use tuple unpacking allowing for:
result = (b for a, b in zip(binary, range(len(binary))) if a)
Further, Python has other builtins that can simplify the code even more.
Enumerate will return a counter plus each element from an iterable allowing the first 3 steps to be simplified to:
# 1 step 1, 2 and 3 can be simplified with enumerate
L = ((i**2, b) for i, b in enumerate(L))
Next sum can be used to replace reduce, sum adds together all numerical values in an iterable:
L = reduce(lambda a, b: a + b, L)
# is equivalent to
L = sum(L)
And putting it all together the entire sequence can be simplified to:
L = sum(2**i for i, b in enumerate(binary) if b)
Hope that helps.
I want to know how can I make a python function that does the same as mapcar of lisp.
From the mapcar lisp documentation :
mapcar operates on successive elements of the lists. function is
applied to the first element of each list, then to the second element
of each list, and so on. The iteration terminates when the shortest
list runs out, and excess elements in other lists are ignored. The
value returned by mapcar is a list of the results of successive calls
to function.
For example,
list1 = [1, 2, 3, 4, 5]
list2 = [5, 4, 3, 2, 1]
def sum(firstNumber, secondNumber):
return firstNumber + secondNumber
sumOfLists = mapcar(sum, list1, list2)
print(sumOfLists)
# [6, 6, 6, 6, 6]
Use map, and also there is an operator for adding operator.add:
>>> import operator
>>> list(map(operator.add, list1, list2))
[6, 6, 6, 6, 6]
From the documentation. map takes a function as first argument, and a variable number of iterable arguments. The key is that the function should take as many arguments as iterables are given to map. That is the only "restriction" to take into account. So, for example:
map(lambda x: x+1, range(10))
map(lambda x, y: x+y, range(10), range(10))
map(lambda x, y, z: x+y+z, range(10), range(10), range(10))
And so on...
Also it can take any other function defined by the user:
def checkString(s):
return isinstance(s, str) and len(s) > 10
>>> list(map(checkString, ["foo", "fooooooooooooooooooooo"]))
[False, True]
This can be achieved in this way: sumOfLists = map(sum, zip(list1, list2))
You also do not need to define the sum function, as it is built-in.
I know that the property map(function,list) applies a function to each element of a single list. But how would it be if my function requires more than one list as input arguments?.
For example I tried:
def testing(a,b,c):
result1=a+b
result2=a+c
return (result1,result2)
a=[1,2,3,4]
b=[1,1,1,1]
c=[2,2,2,2]
result1,result2=testing(a,b,c)
But this only concatenates the arrays:
result1=[1,2,3,4,1,1,1,1]
result2=[1, 2, 3, 4, 2, 2, 2, 2]
and what I need is the following result:
result1=[2,3,4,5]
result2=[3,4,5,6]
I would be grateful if somebody could let me know how would this be possible or point me to a link where my question could be answered in a similar case.
You can use operator.add
from operator import add
def testing(a,b,c):
result1 = map(add, a, b)
result2 = map(add, b, c)
return (result1, result2)
You can use zip:
def testing(a,b,c):
result1=[x + y for x, y in zip(a, b)]
result2=[x + y for x, y in zip(a, c)]
return (result1,result2)
a=[1,2,3,4]
b=[1,1,1,1]
c=[2,2,2,2]
result1,result2=testing(a,b,c)
print result1 #[2, 3, 4, 5]
print result2 #[3, 4, 5, 6]
Quick and simple:
result1 = [a[i] + b[i] for i in range(0,len(a))]
result2 = [a[i] + c[i] for i in range(0,len(a))]
(Or for safety you can use range(0, min(len(a), len(b)))
Instead of list, use array from numpy instead.
list concatenate while arrays add corresponding elements. Here I converted the input to numpy arrays. You can feed the function numpy arrays and avoid the conversion steps.
def testing(a,b,c):
a = np.array(a)
b = np.array(b)
c = np.array(c)
result1=a+b
result2=a+c
return (result1,result2)
a=[1,2,3,4]
b=[1,1,1,1]
c=[2,2,2,2]
result1,result2=testing(a,b,c)
print(result1, result2)
anyone have any idea how to unpack the values in a tuple for a list comprehension?
So a practical example:
def func(x,y):
return x*2, y*2
x = [1, 2, 3]; y = [1, 2, 3]
a, b = [ func(i,j) for i, j in zip(x,y) ]
Unfortunately, that gives me an error sayin' there are too many values to unpack...
I've tried
zip(*func(i,j))
(a,b) = ...
Do you mean the following?:
a, b = zip(*[func(i,j) for i, j in zip(x,y)])
for x1,y1 in [func(i,j) for i, j in zip(x,y)]:
# do something with x1,y1
The problem is that the list comprehension returns something like
[(1,1), (4,4), (6,6),..]
so the list contains more than just two elements.
I don't see why you can't just do:
a = [i*2 for i in x]
b = [i*2 for i in y]
If you are worried about duplicate code, create a function:
def func(l):
return [i*2 for i in l]
a, b = func(x), func(y)
Trying to pack everything in one line, using fancy list unpacking etc., does not necessarily increase readability.