python map function (+ lambda) involving conditionals (if) - python

I'm curious if it's possible to do something with the map()function that I can do via list comprehension.
For ex, take this list comp:
example_list = [x*2 for x in range(5) if x*2/6. != 1]
obviously, this gives me [0, 2, 4, 8].
How do I make the equivalent using the map() function? Doing this gives me a syntax error.
example_map = map(lambda x:x*2 if x*2/6. != 1, range(5))
Just trying to get a better understanding of how to use this function.

You'll have to wrap the map around a filter around the list:
example_map = map(lambda x: x*2, filter(lambda x: x*2/6. != 1, range(5)))

Alternatively, you could filter your map rather than maping your filter.
example_map = filter(lambda x: x/6. != 1, map(lambda x: x*2, range(5)))
Just remember that you're now filtering the RESULT rather than the original (i.e. lambda x: x/6. != 1 instead of lambda x: x*2/6. != 1 since x is already doubled from the map)
Heck if you really want, you could kind of throw it all together with a conditional expression
example_map = map(lambda x: x*2 if x*2/6. != 1 else None, range(5))
But it'll leave you with [0, 2, 4, None, 8]. filter(None, example_map) will drop the Nones and leave you [0, 2, 4, 8] as expected.

Along side the other answers that suggests some solutions the reason of your Syntax Error is that map function :
Apply function to every item of iterable and return a list of the results.
So the result is in a same length as your iterable.and if you use if statement you need to specify an else too.
>>> map(lambda x:x*2 if x*2/6. != 1 else None, range(5))
[0, 2, 4, None, 8]
And as an alternative way you can use itertools.ifilter to filter your iterable :
>>> from itertools import ifilter
>>> map(lambda x:x*2,ifilter(lambda x: x*2/6. != 1,range(5)))
[0, 2, 4, 8]
Note that as you don't need the result of filtered list and you just want to pass it to map it's more efficient that use ifilter because it returns a generator and you can save much memory for long lists ;) (its all in python 2 and in python 3 filter returns generator)

you can do it at two stages, first stage by applying filter on the list and the second stage by applying mapping function on the output list
list(map(lambda x:x*2, filter(lambda x: x*2/6 != 1 , [x for x in range(5)])))
[0, 2, 4, 8]

Related

Sort a list by index with default if index doesn't exist

I have a 2 dimensional list. I want to sort this list by multiple criteria in the sublist, but provide a default if one of the chosen index criteria doesn't exist.
my_list = [[5, 4], [1], [6, 8, 1]]
my_list.sort(key=lambda x: (x[0], x[1])
Obviously, this will throw an out of range error. How can I get around this and provide a default value if the index doesn't exist?
You can write it the explicit way, checking length and using a different value if it's too short:
my_list.sort(key=lambda x: (x[0], x[1] if len(x) > 1 else 12345)
or you can append the fallback value unconditionally, then slice down to the number of elements you care about:
my_list.sort(key=lambda x: [*x, 12345][:2])
In your lambda, you could add two default values (in this case I've used None) to the end of the list ensuring it is at least two values long.
>>> my_list = [[5, 4], [1], [6, 8, 1]]
>>> sorted(my_list, key=lambda x: ((x := [*x, None, None])[0], x[1]))
[[1], [5, 4], [6, 8, 1]]
Requires Python 3.8 or later for := operator.
You can take advantage of the fact that indexing a list with an out-of-bound slice returns an empty list, and use the or operator to make the empty list default to a singleton list enclosing a value you want in its place. Since the or operator is widely used as an idiom to provide default values, this approach makes the code arguably more readable:
DEFAULT = [1]
my_list.sort(key=lambda x: (x[0], x[1:2] or DEFAULT))
Demo: https://replit.com/#blhsing/TornEquatorialCookies

Basic Python manipulation of nested list

For the following nested list, Lst, I need to keep the first inner list, square the second, and cube the last one.
Lst = [[1,2,3],[2,3,4],[3,4,5]]
My current code is squaring all the nested list in the Lst.
list(map(lambda lst: list(map(lambda x: x**2, lst)), Lst))
How can I fix this? I just started learning Python.
Since you're not doing the same operation on each nested list, you shouldn't use map() for the top-level list. Just make a list of results of different mappings for each.
[Lst[0], list(map(lambda x: x**2, lst[1])), list(map(lambda x: x**3, lst[2]))]
However, there's an obvious pattern to this, so you can generalize it using enumerate() and a list comprehension:
[list(map(lambda x: x**i, sublist)) for i, sublist in enumerate(Lst, 1)]
[list(map(lambda x: x**i, l)) for i,l in enumerate(Lst, 1)]
[[1, 2, 3], [4, 9, 16], [27, 64, 125]]
Your processing obviously needs to take into account where in the list you are. Forcing this into a one-liner makes it more dense than it really needs to be, but see if you can follow along with pencil and paper.
[[x if i == 0 else x**2 if i == 1 else x**3 for x in Lst[i]] for i in range(3)]
Demo: https://ideone.com/o8y0ta
... Or, as cleverly suggested in Barmar's answer,
[[x**i for x in Lst[i]] for i in range(3)]
Try indexing the outer list and then call the map function on each index
def square(number) :
return number ** 2
def cube(number) :
return number ** 3
lst = [[1,2,3],[2,3,4],[3,4,5]]
lst[0] = lst[0]
lst[1] = list(map(square, lst[1]))
lst[2] = list(map(cube, lst[2]))
print(lst)

mysterious behaviour of python built-in method filter in for loop

Consider the below fact:
a = list(range(10))
res = list(a)
for i in a:
if i in {3, 5}:
print('>>>', i)
res = filter(lambda x: x != i, res)
print(list(res))
>>> 3
>>> 5
[0, 1, 2, 3, 4, 5, 6, 7, 8]
So neither 3 nor 5 was removed, but 9 is gone...
If i force convert the filter object to list, then it work as expected:
a = list(range(10))
res = list(a)
for i in a:
if i in {3, 5}:
print('>>>', i)
# Here i force to convert filter object to list then it will work as expected.
res = list(filter(lambda x: x != i, res))
print(list(res))
>>> 3
>>> 5
[0, 1, 2, 4, 6, 7, 8, 9]
I can feel this is due to that the filter object is a generator, but cannot exactly interpreter how the generator cause this consistent weird behaviour, please help to elaborate the underlying rationalities.
The behaviour arises from a combination of two facts:
The lambda function contains the variable i taken from the surrounding scope, which is only evaluated at execution time. Consider this example:
>>> func = lambda x: x != i # i does not even need to exist yet
>>> i = 3
>>> func(3) # now i will be used
False
Because filter returns a generator, the function is evaluated lazily, when you actually iterate over it, rather than when filter is called.
The combined effect of these, in the first example, is that by the time that you iterate over the filter object, i has the value of 9, and this value is used in the lambda function.
The desired behaviour can be obtained by removing either (or both) of the two combined factors mentioned above:
In the lambda, force early binding by creating a closure, where you use the value of i as the default value of a parameter (say j), so in place of lambda x: x != i, you would use:
lambda x, j=i: x != j
The expression for the default value (i.e. i) is evaluated when the lambda is defined, and by calling the lambda with only one argument (x) this ensures that you do not override this default at execution time.
or:
Force early execution of all iterations of the generator by converting to list immediately (as you have observed).

How to make a python function that works as 'mapcar' of lisp

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.

Sorting a list based on whether item is odd or even

I am trying to sort a list of numbers depending on whether it is odd or even (even gains higher priority).
Example:
a=[1,2,3,4]
a.sort(key=org(a)) sorted will produce [2,4,1,3]. I want to use the sort method
def org(a):
for i in range(len(a)):
if a[i]%2==0:
b.append(a[i])
b.sort()
else:
c.append(a[i])
c.sort()
print(b+c)
I got this error from running a.sort(key=org(a))
Traceback (most recent call last):
File "<pyshell#80>", line 1, in <module>
a.sort(key=org(a))
TypeError: 'list' object is not callable
I realize that sorting it every time makes it slow. Which other way can I do this without having to sort after every loop?
To sort by "evenness" and then by magnitude, you can use a function that returns a tuple
>>> a=[1,2,3,4]
>>> a.sort(key=lambda x: (x % 2, x))
>>> a
[2, 4, 1, 3]
To sort the odd entries first, you can simply negate the value of the modulus. This is a useful trick for reversing the sort of numeric fields in general.
>>> a.sort(key=lambda x:(-(x % 2), x))
>>> a
[1, 3, 2, 4]
It looks like you were on the right track:
a = [1,2,3,4]
>>> sorted(a,key=lambda x: x%2)
[2, 4, 1, 3]
Here sorted is a function that returns a sorted list. You can also use the sort method, as John said. Apparently if your original list is not sorted, sorted will not work, so you then you would have to do:
a = [3,2,1,4]
a.sort()
newList = sorted(a,key=lambda x: x%2)
at which point John's code is probably cleaner. His can also be implemented with the sorted function though, by doing sorted(a,key=lambda x: (x%2,x)).
one can use helper function from intertools
def partition_by_pred(pred, iterable):
from itertools import tee, filterfalse
t1, t2 = tee(iterable)
return filterfalse(pred, t1), filter(pred, t2)
l, r = partition_by_pred(lambda x: False if x % 2 == 0 else True ,[1,2,3,4] )
print(*l,*r)
2 4 1 3

Categories

Resources