I want to create a function which returns a function creating an iterator (like something from itertools), but with a parameter set by the outer function.
For example, say I want to take a running sum, but exclude values that are larger than a given cutoff (which is the parameter of the function).
So, say I have a list like this:
x = [1, 1, 1, 1, 25, 1, 1]
And I want a function that would take the running sum, but ignore values greater than 10, to give me an output like this:
y = [1, 2, 3, 4, 4, 5, 6]
This code will do the trick:
t = 10
accumulate(x,lambda x,y:x if y>=t else x+y)
But now I want to make a function which returns a function like the above, where I can pass it the value t as the parameter.
This is what I tried:
def sum_small_nums(t):
def F(x):
new_x = accumulate(x,lambda x,y: x if y>=t else x+y)
return F
Unfortunately this doesn't seem to work. I can create a function from the above, but when I try to call it, I don't get the output I am expecting (e.g. I get 'None' instead of a list):
sum_under_10 = sum_small_nums(10)
print(sum_under_10)
x = [1, 1, 1, 1, 25, 1, 1]
x2 = sum_under_10(x)
print(x2)
returns
<function sum_small_nums.<locals>.F at 0x7feab135a1f0>
None
You're close! Need to return the list from the inner function:
def sum_small_nums(t):
def F(x):
new_x = accumulate(x, lambda x, y: x if y >= t else x + y)
return list(new_x)
return F
When you don't return anything from a function, None is implicitly returned.
Related
I wrote a function that changes all instances of y to z in x (where x is a list) but somehow my code is not working. The outcome should have been [1, 'zzz', 3, 1, 'zzz', 3]. I attached my code below any help is appreciated. Thanks in advance.
x = [1, 2, 3, 1, 2, 3]
def changeThem(x,y,z):
replace = {y : z}
for key, value in replace.items():
x = x.replace(key, value)
print(x)
changeThem(x,2,'zzz')
A list does not have .replace() method. How about the following?
x = [1, 2, 3, 1, 2, 3]
def changeThem(x,y,z):
return [z if i == y else i for i in x]
print(changeThem(x, 2, 'zz'))
The function consists of just one line so defining this function might not be even necessary. But I am leaving it in case you would like to call it multiple times.
Your code yields an AttributeError. This is because list does not have a replace method. str has a replace method, so this might be where you're getting confused.
You could accomplish this with a very simple list comprehension:
x = [z if e == y else e for e in x]
Essentially, the above list comprehension states:
For every value e in the list x, replace it with z if the element is equal to y. Otherwise, just keep the element there.
It is also equivalent to the following:
result = []
for e in x:
if e == y:
result.append(z)
else:
result.append(x)
I have some strange behavior on python 3.7 with a nested list comprehension that involves a generator.
This works:
i = range(20)
n = [1, 2, 3]
result = [min(x + y for x in i) for y in n]
It does not work if i is a generator:
i = (p for p in range(20))
n = [1, 2, 3]
result = [min(x + y for x in i) for y in n]
This raises a ValueError: min() arg is an empty sequence
Now even if the generator i is wrapped with list it still creates the same error:
i = (p for p in range(20))
n = [1, 2, 3]
result = [min(x + y for x in list(i)) for y in n]
Is this a python bug or is it expected behavior? If it is expected behavior, can you explain why this does not work?
In i = range(20) the range(20) is a promise to generate a generator.
While i = (p for p in range(20)) is already a generator.
Now write your list expression as:
for y in [1, 2, 3]:
print(min(x + y for x in i))
## 1
## ...
## ValueError: min() arg is an empty sequence
You get a 1 printed, but (the generator is exhausted in the first call)
and then you get in the next round a
ValueError: min() arg is an empty sequence
because the generator i was already consumed in the first for-loop call for y as 1.
While if i is defined as range(20),
everytime the for x in i is called, the generator is re-created again and again.
You can imitate what range(20) is doing by:
def gen():
return (p for p in range(20))
for y in [1, 2, 3]:
print(min(x + y for x in gen()))
# range() like gen() is a promise to generate the generator
## 1
## 2
## 3
Now the generator is created everytime anew.
But in fact, range is even cooler, if you do:
i = range(20)
for y in [1, 2, 3]:
print(min(x + y for x in i))
## 1
## 2
## 3
The i inside the innerst generator is not a function call.
But despite of that it creates - when evaluted - a new generator -
at least when used as an iterable within a for loop.
This is actually implemented in Python using a class and by defining the __iter__() method. Which defines the behaviour in interators - here especiall a lazy behavior.
To imitate this behavior, we can generate a lazy generator (lazy_gen).
class lazy_gen:
def __init__(self):
pass
def __iter__(self): # everytime when used as an iterator
return self.gen() # recreate the generator # real lazy behavior
def gen(self):
return (p for p in range(20))
Which we can use like:
i = lazy_gen()
for y in [1, 2, 3]:
print(min(x + y for x in i))
## 1
## 2
## 3
So this reflects even better the range() behavior.
Other languages (functional languages) like Lisp family languages (common-lisp, Racket, Scheme, Clojure), R, or Haskell
have a better control over evaluation - thus over lazy evaluation and promises. But in Python, for such implementations and fine grained control, one has to take resort in OOP.
My range function and class
Finally, I figured out how the range function must have been realized roughly.
(For fun, though I could have looked it up in the source code of Python I know - but sometimes reasoning is fun.)
class Myrange:
def __init__(self, start, end, step):
self.start = start
self.end = end
self.step = step
def __iter__(self):
return self.generate_range()
def generate_range(self):
x = self.start - self.step
while x + self.step < self.end:
x = x + self.step
yield x
def __repr__(self):
return "myrange({}, {})".format(self.start, self.end)
def myrange(start=None, end=None, step=1):
if start is None and end is None:
raise "Please provide at least one number for the range-limits."
elif start is not None and end is None:
_start = 0
_end = start
elif start is not None and end is not None:
_start = start
_end = end
else:
_start = 0
_end = end
_step = step
return Myrange(_start, _end, _step)
One can use it exactly like the range function.
i = myrange(20)
n = [1, 2, 3]
result = [min(x + y for x in i) for y in n]
result
## [1, 2, 3]
i
## myrange(0, 20) # representation of a Myrange object.
myrange(20)
## myrange(0, 20)
list(myrange(3, 10))
## [3, 4, 5, 6, 7, 8, 9]
list(myrange(0, 10))
## [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
list(myrange(10))
## [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
list(myrange(0, 10, 2))
## [0, 2, 4, 6, 8]
list(myrange(3, 10, 2))
## [3, 5, 7, 9]
In both of your last examples, you try to iterate on the generator again after it got exhausted.
In your last example, list(i) is evaluated again for each value of y, so i will be exhausted after the first run.
You have to make a list of the values it yields once before, as in:
i = (p for p in range(20))
n = [1, 2, 3]
list_i = list(i)
result = [min(x + y for x in list_i) for y in n]
The generator is emptied after the first for loop for both for x in i or for x in list(i), instead you need to convert the generator to a list, (which essentially iterates over the generator and empties it) beforehand and use that list
Note that this essentially defeats the purpose of a generator, since now this becomes the same as the first approach
In [14]: list(range(20)) == list(p for p in range(20))
Out[14]: True
Hence the updated code will be
#Create generator and convert to list
i = list(p for p in range(20))
n = [1, 2, 3]
#Use that list in the list comprehension
result = [min(x + y for x in i) for y in n]
print(result)
The output will be
[1, 2, 3]
Hence the better approach hence is to stick with the first approach itself, or you can have the generator inline, which, again is the same as the first approach with range
n = [1, 2, 3]
result = [min(x + y for x in (p for p in range(20))) for y in n]
print(result)
#[1, 2, 3]
I am using map to process a list in Python3.6:
def calc(num):
if num > 5:
return None
return num * 2
r = map(lambda num: clac(num), range(1, 10))
print(list(r))
# => [2, 4, 6, 8, 10, None, None, None, None]
The result I expect is: [2, 4, 6, 8, 10].
Of course, I can use filter to handle map result. But is there a way for map to return directly to the result I want?
map cannot directly filter out items. It outputs one item for each item of input. You can use a list comprehension to filter out None from your results.
r = [x for x in map(calc, range(1,10)) if x is not None]
(This only calls calc once on each number in the range.)
Aside: there is no need to write lambda num: calc(num). If you want a function that returns the result of calc, just use calc itself.
Not when using map itself, but you can change your map() call to:
r = [calc(num) for num in range(1, 10) if calc(num) is not None]
print(r) # no need to wrap in list() anymore
to get the result you want.
Being new to python I am just trying to figure out the difference between filter() and map().
I wrote a sample script as follows:
def f(x): return x % 2 == 0
def m(y): return y * 2
list = [1,2,3,4]
flist = filter(f, list)
print(list)
print(flist)
mlist = map(m, list)
print(list)
print(mlist)
We see that to both the filter and map we pass a list and assign their output to a new list.
Output of this script is
[1, 2, 3, 4]
[2, 4]
[1, 2, 3, 4]
[2, 4, 6, 8]
Question arises is that function call of both filter and map looks same so how will they behave if we interchange the contents of functions passed to them.
def f(x): return x * 2
def m(y): return y % 2 == 0
list = [1,2,3,4]
flist = filter(f, list)
print(list)
print(flist)
mlist = map(m, list)
print(list)
print(mlist)
This results in
[1, 2, 3, 4]
[1, 2, 3, 4]
[1, 2, 3, 4]
[False, True, False, True]
This shows filter evaluates the function and if true it returns back the passed element.
Here the function
def f(x): return x * 2
evaluates to
def f(x): return x * 2 != 0
In contrast map evaluates the function expression and returns back the result as items.
So filter always expects its function to do comparison type of task to filter out the elements while map expects its functions to evaluate a statement to get some result.
Is this understanding correct?
They both work a little bit differently but you've got the right idea.
Map takes all objects in a list and allows you to apply a function to it
Filter takes all objects in a list and runs that through a function to create a new list with all objects that return True in that function.
Here's an example
def square(num):
return num * num
nums = [1, 2, 3, 4, 5]
mapped = map(square, nums)
print(*nums)
print(*mapped)
The output of this is
1 2 3 4 5
1 4 9 16 25
Here's an example of filter
def is_even(num):
return num % 2 == 0
nums = [2, 4, 6, 7, 8]
filtered = filter(is_even, nums)
print(*nums)
print(*filtered)
The output of this would be
2 4 6 7 8
2 4 6 8
In map: Function will be applied to all objects of iterable.
In filter: Function will be applied to only those objects of iterable who goes True on the condition specified in expression.
As per my understanding below are the difference between map and filter:
def even(num):
if(num % 2 == 0):
return 'Even'
num_list = [1,2,3,4,5]
print(list(filter(even,num_list))) ->>>>>>>output: [2, 4]
print(list(map(even,num_list))) ->>>>>>> output: [None, 'Even', None, 'Even', None]
So, we can say that:
filter(): formats new list that contains elements which satisfy specific condition.
map(): function iterates through a all items in the given iterable and executes a function which we passed as an argument.
I think yes you got the picture pretty much.
both Map and filter are ways of applying function to iterables.
in Map you can use multiple iterables
definition : map(function_object, iterable1, iterable2,...)
whereas
in filter only one iterable can be used
definition : filter(function_object, iterable)
further in filter the function_object has to return boolean only.
for sake of example following is the Map with multiple iterables as input
list_a = [1, 2, 3]
list_b = [10, 20, 30]
map(lambda x, y: x + y, list_a, list_b) # Output: [11, 22, 33]
The filter() and map() functions are a little bit different.
While Maps takes a normal function, Filter takes Boolean functions. As a matter of fact, filter are maps with conditional logic, a Boolean logic.
Your example is too accurate.
In filter function your supposed to pass a function and a list(the function must evaluate to true or false). If the element passed in the function returns true the filter function will put the element passed into a new list. Where as map function will take an element pass it through a function and return the output of the function and store that to the new list.
map(): Function will be applied to all objects of iterable, we can use as many literables as wee needed
filter(): Function will be applied to only those objects of iterable and added to result which item is True, we can use only one literable
In the below, code 0 is not add in the filter function because 0 is a representation for False in some cases so it is not added to the filter and added in the map function result
def check(num):
return num*1
nums = [0,2, 4, 6, 7, 8]
result = filter(check, nums)
print(list(result))
def check(num):
return num*1
nums = [0,2, 4, 6, 7, 8]
result = map(check, nums)
print(list(result))
map() applies any applicable logic presented to any number of arguments of type list and returns an iterable containing values mapped to each respective members of the argument list(s).
example:
m = map(lambda x,y: 10+x+y, [1,2,3,4],[10,20,30,40])
print(list(m))
output:
[21, 32, 43, 54]
filter() applies the condition specified to one argument of type list and returns an iterable containing values that satisfy the specified condition and thus selected from the argument.
example:
f = filter(lambda x: x<3, [1,2,3,4])
print(list(f))
output:
[1, 2]
The main difference between a map and a filter is the return of values. A map will always have a representation for elements in the list. The filter will filter out the only elements that will meet the conditions in the function.
def checkElementIn(a):
nameList = ['b','a','l','l']
if a in nameList:
return a
testList = ['r','e','d','b','a','l','l']
m_list = map(checkElementIn,testList)
for i in m_list:
print(i)
None
None
None
b
a
l
l
f_list = filter(checkElementIn,testList)
for i in f_list:
print(i)
b
a
l
l
Those are completely different
just take a look at this clear example down below:
def sqr(x):
return x%2==0
mp = map(sqr, [-1,0,1,2,3,4,5,6])
print(list(mp))
[False, True, False, True, False, True, False, True]
fl = filter(sqr, [-1,0,1,2,3,4,5,6])
print(list(fl))
[0, 2, 4, 6]
as you can see in this clear example the filter doesn't care about the function results! It just checks which one of the list items would be true belonging to the calculation def, and the return is a list [0, 2, 4, 6] which means we have got a true result of numbers
I want to replicate the following JavaScript code in Python:
let a = [0, 4, 5]
b = a.map(x => {
if(x < 3) return 0
else return 1
})
Any idea how I can do this?
I'm not sure how execute a code block in a map function.
You can either make a function, or use a lambda function like this:
>>> a = [0, 4, 5]
>>> b = map(lambda x: 0 if x < 3 else 1, a)
>>> b
[0, 1, 1]
The only kind of anonymous functions in Python are lambdas, and they're limited to being only an expression, if you want a proper function you have to give it a name:
def map_f(x):
if x < 3:
return 0
else:
return 1
b = map(map_f, a)
Personally, I prefer list comprehension to the map function.
>>> a = [0, 4, 5]
>>> [int(x >= 3) for x in a]
[0, 1, 1]
They allow you to use whatever expression you want without having to create a function.