Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to implement a nested for loop in functional programming in python?

I was thinking of applying the map function twice in order to allow it to act as a double for loop but I don't know if that makes sense. Is that the way to go about it?

For example, this is what I am working on:

In imperative:

def degree(A):
    n = len(A)
    t = []
    for i in range(n):
        d = 0
        for j in range(n):
            d+=A[i][j]
        t.append(d)

    return t

In functional:

def degree(A):
    n = len(A)
    t = []
    map(lambda x,y:x+y,A)

If it was a single for loop then I would approach it as I did above. So I was trying to implement a double map, but I do not know what how to structure that. Any help would be appreciated!

like image 386
aa1 Avatar asked Nov 01 '25 06:11

aa1


1 Answers

You are summing the inner lists A, so just apply sum to each nested list in A:

def degree(A):
    return map(sum, A)

You could also consider using a list comprehension or generator expression (depending on whether or not you need to produce the result lazily (map() in Python 2 produces a list, in Python 3 it works lazily):

def degree(A):
    # returns a list
    return [sum(row) for row in A]

def degree(A):
    # returns a generator
    return (sum(row) for row in A)

You can otherwise produce i and j as a cartesian product, using itertools.product(); however, you'd be passing in a tuple of integers to the map callable:

from itertools import product

map(lambda ij: A[ij[0]][ij[1]] ** 2, product(range(len(A)), 2))

This can be remedied by using itertools.starmap() instead:

from itertools import product, starmap

starmap(lambda i, j: A[i][i] ** 2, product(range(len(A)), 2))

Neither produces a sum; I demoed a lambda that produces the square of the innermost values instead, so you get one long sequence of all values, squared, without distinction between rows. That's how mapping works, it produces a value per item processed in the input.

You could also just nest the map() calls; put the inner map() in the callable for the outer map():

map(lambda r: map(lambda v: v ** 2, r), A)

but note that this then produces a lazy sequence of lazy objects in Python 3. Again, summing doesn't make sense in this scenario, as there is no accumulation of results.

For a generic cumulation of results across a sequence, you want to use the functools.reduce() function; that callable applies a callable on a running result and the next value in a sequence. You can produce a sum with your lambda x, y: x + y function and map():

map(lambda r: reduce(lambda x, y: x + y, r, 0), A)

But for just summing, the reduce(lambda x, y: x + y, <iterable>, 0) syntax is just a verbose and slower way of spelling sum(<iterable>).

like image 121
Martijn Pieters Avatar answered Nov 02 '25 20:11

Martijn Pieters