Self Implementation of map() - python

I have to Implement by myself new map() that can get more than one function.
I wrote this code:
def map(iterable, *callbacks):
temporary = []
callbacksList = list(callbacks)
for func in callbacksList:
for item in iterable:
temporary.append(func(item))
callbacksList = callbacksList[1:]
iterable = temporary
temporary = []
return iterable
The code works fine in this case:
c = "hello"
print(map(c,str.upper,ord,chr)) # => ['H','E','L','L','O']
but in this case:
c = "hello"
print(map(c,str.upper,chr,ord))
I got an error "an integer is required (got type str)" - because of chr function that gets str and not int.
I don't understand how can I Adjust my code to work with both cases and be more generic.
Thanks for helpers.

Since your callbacks seem to be applied one after another, why not make this a generator and swap the two for loops (so your iterable can also be a generator):
def map(iterable, *callbacks):
for item in iterable:
for f in callbacks:
item = f(item)
yield item
list(map("hello", str.upper, ord, chr))
# ['H', 'E', 'L', 'L', 'O']
But just like your code this requires that the output of each function is also a valid input for the following function. If this is not the case, you could ignore all functions that raise an exception:
def map2(iterable, *callbacks):
for item in iterable:
for f in callbacks:
try:
item = f(item)
except (TypeError, ValueError): # might want to be more generic than this, depending on your functions
pass
yield item
list(map2("hello", str.upper, chr, ord))
# [72, 69, 76, 76, 79]
But it really depends on your usecase what the right action is in this case.

You are effectively composing your list of callbacks; your call
map(c, str.upper, ord, chr)
should be equivalent to map(c, lambda x: chr(ord(str.upper(c)))). However, your other attempt
map(c, str.upper, chr, ord)
is equivalent to map(c, lambda x: ord(chr(str.upper(c))), and ord(chr('x')) simply isn't defined; chr cannot take a string as an argument.
That said, you can simplify your definition by composing the functions first, then using the built-in map to apply the composed function.
def map(iterable, *callbacks):
# The identity function i = lambda x: x is the identity for function composition.
# That is, f(i(x)) == i(f(x)) == f(x)
f = lambda x: x
for g in callbacks:
# The g=g is necessary due to how Python handles name lookups
f = lambda x, g=g: g(f(x))
return map(f, iterable)
You can also use the functools.reduce function to perform the composition.
def compose(f,g):
def _(x):
return f(g(x))
return _
def ident(x):
return x
def map(iterable, *callbacks):
f = functools.reduce(compose, callbacks, ident)
return map(f, iterable)
One important note: this style of programming is not very efficient in Python, due to the extra anonymous functions that get inserted into the call chain and the relatively high cost of a function call.

Related

apply list of function to an iterable one after another in python

I have a function process which takes in a list of functions and an iterable. I want to apply that every function in that list to the iterable one after another. I wrote this which works fine but...
def process(list_of_funcs, string):
for func in list_of_funcs:
string = ''.join(list(map(func, string)))
return string
ans = process([lambda c: c.upper(), lambda c: c + '0'], "abcd")
print(ans) # A0B0C0D0
I want to skip the for loop (and do it the functional programming way). Is there a way for that in python?
You may use functools.reduce with parameters
as function : apply the current function on the previous result
as sequence : the list of functions
as initial value : the initial string
def process(list_of_funcs, string):
return reduce(lambda res, f: ''.join(map(f, res)), list_of_funcs, string)
Note : no need of intermediate list, the join takes an iterator
Here is an example with 3 functions and it gives the same ouput as your initial for-loop solution
fcts = [lambda c: c.upper(), lambda c: c + '0', lambda c: c * 2]
ans = process(fcts, "abcd")
print(ans) # AA00BB00CC00DD00

How can I pass method as function parameter without 'lambda' keyword?

Can I somehow refer to a method without using the lambda keyword?
Say we have following example code:
class AbstractDummy:
def size(self):
raise NotImplementedError
class Dummy1(AbstractDummy):
def size(self):
return 10
class Dummy2(AbstractDummy):
def size(self):
return 20
If I have my example objects:
dummies1 = [Dummy1(), Dummy1(), Dummy1()]
dummies2 = [Dummy2(), Dummy2()]
Then if I want to map them, and I can do that with extracted function parameter to save me some characters:
f = lambda x : x.size()
map(f, dummies1)
map(f, dummies2)
Question here: can I somehow avoid this temporary f and/or lambda keyword?
To make a small comparison, in Java it would be possible to refer to AbstractDummy::size and so the invocation would look a bit like print(map(AbstractDummy::size, dummies1).
The operator module provides methodcaller for this.
from operator import methodcaller
f = methodcaller('size')
results1 = [f(x) for x in dummies1]
results2 = [f(x) for x in dummies2]
though [x.size() for x in ...] is simpler, as in C_Z_'s answer. methodcaller is useful for when you need a function as a function argument, for example
# Sort some_list_of_objects on return value of each object's `a` method.
sorted_list = sorted(some_list_of_objects, key=methodcaller('a'))
In this case you would probably want to use a list comprehension
[x.size() for x in dummies1]
[x.size() for x in dummies2]

How to take the logical and of a list of boolean functions in python

Say I have a list of functions li = [fun1, fun2, ..., funk] that take one argument and return a boolean. I'd like to compose them into a single function that returns the logical and of the return values of each of the fun's when evaluated at its argument. (in other words I'd like to have fun(x) = fun1(x) and fun2(x) and ... and funk(x).)
Is there an elegant way of doing this?
Use all to create the composite function
def func(x, lst):
#lst is the list of functions and x is used as an argument for functions
return all(fun(x) for fun in lst)
And then call it as
func(x,[fun1, fun2, fun3,...., funk])
If a lambda function is needed, you can do the following, however it is against PEP-8 guidelines
Always use a def statement instead of an assignment statement that binds a lambda expression directly to an identifier.
func = lambda x:all(fun(x) for fun in lst)
And call it as
func(x)
all will do it
all(func(x) for func in li)

map with lambda vs map with function - how to pass more than one variable to function?

I wanted to learn about using map in python and a google search brought me to http://www.bogotobogo.com/python/python_fncs_map_filter_reduce.php which I have found helpful.
One of the codes on that page uses a for loop and puts map within that for loop in an interesting way, and the list used within the map function actually takes a list of 2 functions. Here is the code:
def square(x):
return (x**2)
def cube(x):
return (x**3)
funcs = [square, cube]
for r in range(5):
value = map(lambda x: x(r), funcs)
print value
output:
[0, 0]
[1, 1]
[4, 8]
[9, 27]
[16, 64]
So, at this point in that tutorial, I thought "well if you can write that code with a function on the fly (lambda), then it could be written using a standard function using def". So I changed the code to this:
def square(x):
return (x**2)
def cube(x):
return (x**3)
def test(x):
return x(r)
funcs = [square, cube]
for r in range(5):
value = map(test, funcs)
print value
I got the same output as the first piece of code, but it bothered me that variable r was taken from the global namespace and that the code is not tight functional programming. And there is where I got tripped up. Here is my code:
def square(x):
return (x**2)
def cube(x):
return (x**3)
def power(x):
return x(r)
def main():
funcs = [square, cube]
for r in range(5):
value = map(power, funcs)
print value
if __name__ == "__main__":
main()
I have played around with this code, but the issue is with passing into the function def power(x). I have tried numerous ways of trying to pass into this function, but lambda has the ability to automatically assign x variable to each iteration of the list funcs.
Is there a way to do this by using a standard def function, or is it not possible and only lambda can be used? Since I am learning python and this is my first language, I am trying to understand what's going on here.
You could nest the power() function in the main() function:
def main():
def power(x):
return x(r)
funcs = [square, cube]
for r in range(5):
value = map(power, funcs)
print value
so that r is now taken from the surrounding scope again, but is not a global. Instead it is a closure variable instead.
However, using a lambda is just another way to inject r from the surrounding scope here and passing it into the power() function:
def power(r, x):
return x(r)
def main():
funcs = [square, cube]
for r in range(5):
value = map(lambda x: power(r, x), funcs)
print value
Here r is still a non-local, taken from the parent scope!
You could create the lambda with r being a default value for a second argument:
def power(r, x):
return x(r)
def main():
funcs = [square, cube]
for r in range(5):
value = map(lambda x, r=r: power(r, x), funcs)
print value
Now r is passed in as a default value instead, so it was taken as a local. But for the purposes of your map() that doesn't actually make a difference here.
Currying is another option. Because a function of two arguments is the same as a function of one argument that returns another function that takes the remaining argument, you can write it like this:
def square(x):
return (x**2)
def cube(x):
return (x**3)
def power(r):
return lambda(x): x(r) # This is where we construct our curried function
def main():
funcs = [square, cube]
for y in range(5):
value = map(power(y), funcs) # Here, we apply the first function
# to get at the second function (which
# was constructed with the lambda above).
print value
if __name__ == "__main__":
main()
To make the relation a little more explicit, a function of the type (a, b) -> c (a function that takes an argument of type a and an argument of type b and returns a value of type c) is equivalent to a function of type a -> (b -> c).
Extra stuff about the equivalence
If you want to get a little deeper into the math behind this equivalence, you can see this relationship using a bit of algebra. Viewing these types as algebraic data types, we can translate any function a -> b to ba and any pair (a, b) to a * b. Sometimes function types are called "exponentials" and pair types are called "product types" because of this connection. From here, we can see that
c(a * b) = (cb)a
and so,
(a, b) -> c ~= a -> (b -> c)
Why not simply pass the functions as part of the argument to power(), and use itertools.product to create the required (value, func) combinations?
from itertools import product
# ...
def power((value, func)):
return func(value)
for r in range(5):
values = map(power, product([r], funcs))
print values
Or if you don't want / require the results to be grouped by functions, and instead want a flat list, you could simply do:
values = map(power, product(range(5), funcs))
print values
Note: The signature power((value, func)) defines power() to accept a single 2-tuple argument that is automatically unpacked into value and func.
It's equivalent to
def power(arg):
value, func = arg

Automatically use list comprehension/map() recursion if a function is given a list

As a Mathematica user, I like functions that automatically "threads over lists" (as the Mathematica people call it - see http://reference.wolfram.com/mathematica/ref/Listable.html). That means that if a function is given a list instead of a single value, it automatically uses each list entry as an argument and returns a list of the results - e.g.
myfunc([1,2,3,4]) -> [myfunc(1),myfunc(2),myfunc(3),myfunc(4)]
I implemented this principle in Python like this:
def myfunc(x):
if isinstance(x,list):
return [myfunc(thisx) for thisx in x]
#rest of the function
Is this a good way to do it? Can you think of any downsides of this implementation or the strategy overall?
If this is something you're going to do in a lot of functions, you could use a Python decorator. Here's a simple but useful one.
def threads_over_lists(fn):
def wrapped(x, *args, **kwargs):
if isinstance(x, list):
return [fn(e, *args, **kwargs) for e in x]
return fn(x, *args, **kwargs)
return wrapped
This way, just adding the line #threads_over_lists before your function would make it behave this way. For example:
#threads_over_lists
def add_1(val):
return val + 1
print add_1(10)
print add_1([10, 15, 20])
# if there are multiple arguments, threads only over the first element,
# keeping others the same
#threads_over_lists
def add_2_numbers(x, y):
return x + y
print add_2_numbers(1, 10)
print add_2_numbers([1, 2, 3], 10)
You should also consider whether you want this to vectorize only over lists, or also over other iterable objects like tuples and generators. This is a useful StackOverflow question for determining that. Be careful, though- a string is iterable, but you probably won't want your function operating on each character within it.
That's a good way to do it.
However, you would have to do it for each function you write.
To avoid that, you could use a decorator like this one :
def threads(fun):
def wrapper(element_or_list):
if isinstance(element_or_list, list):
return [fun(element) for element in element_or_list]
else:
return fun(element_or_list)
return wrapper
#threads
def plusone(e):
return e + 1
print(plusone(1))
print(plusone([1, 2, 3]))

Categories