Mr Krabs
Mr Krabs

Reputation: 13

Using map and filter function on a sublist in python

L = [[5, 0, 6], [7, 22], [0, 4, 2], [9, 0, 45, 17]]

I do have this list and my task is to remove the 0's. I have to use both map() and filter() function.

The hint is that this task is solvable with a single expression using map, filter and lambda expressions.

I have been trying to figure this out for quite a while but I just don't get it. You don't have to solve it completely, but help would be appreciated.

I assume I use map() to iterate over the outer lists, but how do I call filter() with the sublist?

L2 = map(lambda x: filter(lambda x: x<>0 ,L),L)

Upvotes: 1

Views: 1761

Answers (4)

mhawke
mhawke

Reputation: 87084

You can use the fact that if the first argument to filter() is None then only those items that are "true" will be retained. 0 is considered false, so 0 will be removed.

A solution can be written like this:

>>> L = [[5, 0, 6], [7, 22], [0, 4, 2], [9, 0, 45, 17]]
>>> map(lambda l: filter(None, l), L)
[[5, 6], [7, 22], [4, 2], [9, 45, 17]]

If you are using Python 3 then you can call list() on the result of the filter() and the map() to get the required list:

>>> map(lambda l: filter(None, l), L)
<map object at 0x7fb34856be80>
>>> list(map(lambda l: list(filter(None, l)), L))
[[5, 6], [7, 22], [4, 2], [9, 45, 17]]

Now that's getting less readable. A list comprehension is probably better.

>>> [[item for item in l if item] for l in L]
[[5, 6], [7, 22], [4, 2], [9, 45, 17]]

Upvotes: 1

Adam Smith
Adam Smith

Reputation: 54213

The key to me is to think about types, which is a somewhat foreign concept in Python.

map takes a function and an iterable, and returns an iterable that is the result of applying that function to each element of the iterable argument.

map(f: "some function",
    lst: "some iterable") -> "(f(e) for e in lst)"

in this case, the elements of your outer lists are themselves lists! And you're planning to apply the filter function to each to remove the zeroes. filter expects a function (that itself expects an element, then returns True if that element should be in the result, or False if it should be removed) and a list of those elements.

filter(f: "some_func(e: 'type A') -> Bool",
       lst: "some_iterable containing elements of type A") ->
       "(e for e in lst if f(e))":

Your filter function then is just filter(lambda x: x != 0, some_list), or lambda sublst: filter(lambda x: x!=0, sublst). Apply that in the map and you'll get:

map(lambda sublst: filter(lambda x: x!=0, sublst), lst)

or

[[x for x in xs if x!=0] xs in xss]

This is much easier to express in Haskell, which deals with map and filter much more naturally.

map (filter (/=0)) lst
-- or still with a list comprehension
[[x | x <- xs, x!=0] | xs <- xss]

Upvotes: 1

Ilya Miroshnichenko
Ilya Miroshnichenko

Reputation: 257

You can use None argument in filter function and do something like

[list(filter(None, i)) for i in a]

Upvotes: 0

Cory Kramer
Cory Kramer

Reputation: 117886

Using map and filter you could write the following

>>> list(map(lambda i: list(filter(lambda i: i != 0, i)), L))
[[5, 6], [7, 22], [4, 2], [9, 45, 17]]

For what it's worth, I'd prefer a nested list comprehension

>>> [[i for i in j if i != 0] for j in L]
[[5, 6], [7, 22], [4, 2], [9, 45, 17]]

Upvotes: 2

Related Questions