Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Using recursion with map in python

I am trying to learn functional programming concepts. An exercise, Flatten a nested list using map/reduce. My code.

lists = [ 1 , 2 , [ 3 , 4, 5], 6, [7, 8, 9] ]
def flatten(lists):
      return map(lambda x: flatten(x) if isinstance(x,list) else x, lists)

print flatten(lists)

I get output same as input. What did i do wrong ? How recursion works with map() ?

like image 529
s007 Avatar asked Nov 24 '15 08:11

s007


People also ask

Is map a recursive function?

The map function is an example of a recursive function on arrays. It is used to transform the elements of an array by applying a function to each element in turn.

What does map () do in Python?

Python's map() is a built-in function that allows you to process and transform all the items in an iterable without using an explicit for loop, a technique commonly known as mapping. map() is useful when you need to apply a transformation function to each item in an iterable and transform them into a new iterable.

What does map () return in Python?

map() function returns a map object(which is an iterator) of the results after applying the given function to each item of a given iterable (list, tuple etc.)

Can map () be used on dictionary Python?

We can use the Python built-in function map() to apply a function to each item in an iterable (like a list or dictionary) and return a new iterator for retrieving the results. map() returns a map object (an iterator), which we can use in other parts of our program.


3 Answers

Here's a solution that uses both map and reduce:

def flatten(seq):
    return reduce(operator.add, map(
        lambda x: flatten(x) if isinstance(x,list) else [x],
        seq))

As Martijn said, map produces the same number of items out as it receives on its input, so the outer step needs to be the reduce call that produces a single output for all of the inputs. map can be used here instead to make all of the input consistent: i.e. a sequence of lists.

like image 160
Duncan Avatar answered Nov 14 '22 23:11

Duncan


You can't solve this problem with map(). The recursive calls return a list, so for a list in the input you replaced the result with another list. map() always has to produce the same number of elements in the output as it was given in the input, after all.

With reduce() you can append more elements to an existing list:

def flatten(lists):
    return reduce(lambda res, x: res + (flatten(x) if isinstance(x, list) else [x]), lists, [])

This starts with an empty list, and appends elements to that for each element in lists. If that element is a list itself, recursion is used.

This produces the expected output:

>>> def flatten(lists):
...     return reduce(lambda res, x: res + (flatten(x) if isinstance(x, list) else [x]), lists, [])
...
>>> lists = [ 1 , 2 , [ 3 , 4, 5], 6, [7, 8, 9] ]
>>> flatten(lists)
[1, 2, 3, 4, 5, 6, 7, 8, 9]
like image 39
Martijn Pieters Avatar answered Nov 14 '22 23:11

Martijn Pieters


Since you are using map in your function it returns a list even when you call call the function in recursively.

So instead of using map or reduce which are not pythonic ways for flattening a nested list you can use a generator function:

>>> def flatten(lists):
...     for sub in lists:
...         if isinstance(sub,list):
...            for i in sub:
...                 yield i
...         else:
...            yield sub
... 
>>> 
>>> list(flatten(lists))
[1, 2, 3, 4, 5, 6, 7, 8, 9]

If you still want to sue map function you can use following approach:

>>> def flatten(lists,total=[]):
...       map(lambda x: total.extend(x) if isinstance(x,list) else total.append(x), lists)
...       return total
... 
>>> flatten(lists)
[1, 2, 3, 4, 5, 6, 7, 8, 9]
like image 29
Mazdak Avatar answered Nov 14 '22 23:11

Mazdak