1

I want to take a nested list

[[[1,2],[4,5]], 1, [1,3,4],[2,3,4]]

go in there recursively, modify each value, and then return a similar list. For example say i wanted to add 1 to each value the output would be

[[[2,3],[5,6]], 2, [2,4,5],[3,4,5]]

I've made some progress doing this with making a recursive function where i test if it's a list or a element to modify. I'm stumped when it comes to how to compile the list again. Isn't there a simple way to do this? The following code is what i have so far.

def add1(nodelist):
    list_of_lists = []
    name_nodes.nodes = []
    def recurse_list(nodelist):
        name_nodes.nodes = []
        edit_list = False
        for r in nodelist:
            if type(r) == list:
                recurse_list(r)
            else:
                edit_list = True
                name_nodes.nodes.append(r+1)
        if edit_list == True:
            list_of_lists.append(name_nodes.nodes)
    recurse_list(nodelist)
    return list_of_lists

This code gets me the following output

[[2, 3], [5, 6, 2], [2, 4, 5], [3, 4, 5], [3, 4, 5]]

I'm surprised there's not some module or some built in functionality to better handle nested lists because there are so many questions handling similar but different behavior. The closest question i could find is here. But that just didn't have exactly what i was looking for. Thanks for any answers.

Community
  • 1
  • 1
raz
  • 151
  • 1
  • 9
  • "if it's a list or a [sic] element to modify" -- this cannot always be done in a 100%-sure manner in Python. – Cong Ma Oct 15 '15 at 18:47

2 Answers2

3
def add1(L):
    for i, elem in enumerate(L):
        if isinstance(elem, int):
            L[i] += 1
        else:
            L[i] = add1(elem)
    return L

Output:

>>> L = [[[1,2],[4,5]], 1, [1,3,4],[2,3,4]]
>>> add1(L)
[[[2, 3], [5, 6]], 2, [2, 4, 5], [3, 4, 5]]
inspectorG4dget
  • 110,290
  • 27
  • 149
  • 241
  • It's so beautiful i'm going to cry. I made a few modifications. I changed `L[i] += 1` to `L[i] = func(elem)` and changed `isinstance(elem, int)` to `not isinstance(elem, list)` added func in the arguement list and renamed it to nmap. Now i can changed a nested list easily. Thank you so much! – raz Oct 15 '15 at 19:30
0

Actually, I've been thinking about this lately. Here's a part of the code I've written for this, an excerpt taken from some demonstration. The function nmap() works like the map() built-in function, but it works with nested lists.

import functools


def mapper_nester(function):
    @functools.wraps(function)
    def wrapper(*point):
        try:
            res = function(*point)
        except TypeError:
            res = map(mapper_nester(function), *point)
        return res
    return wrapper


def nmap(function, *seq):
    """nmap(funtion, seq[, seq ...]) -> nested list of similar structure."""
    return map(mapper_nester(function), *seq)

>>> nested_list = [0, [1], [[[[2]]]],
                   [3, [], [4, 5]],
                   [6, [7, 8],
                    9, [[[]], 10, []]], 11,
                   [], [], [12]]
>>> nmap(lambda x: x + 1, nested_list)
[1,
 [2],
 [[[[3]]]],
 [4, [], [5, 6]],
 [7, [8, 9], 10, [[[]], 11, []]],
 12,
 [],
 [],
 [13]]

This is a recursive function that traverses the nested (recursive) structure.

Pros:

Cons:

  • It is subjected to the recursion limit, so not really useful for deeply nested lists.
  • In Python context, recursive functions are frowned upon in general.
  • This function uses TypeError to check for the node's "type" (atom or collection-of-atoms), but this is not always reliable (and is dependent on what the mapped function actually do), especially with Python duck typing.

Actually I've written a lot more code just to address the last issue, but it's quite cumbersome to put into here.[1]

[1] What it does is to create a temporary, limited "typed universe" which clearly distinguishes atoms from collections-of-atoms (this is done in an ugly manner, using isinstance() and friends, and the creation of this "typed universe" can be customized), and then to lift both the data and the to-be-mapped function into this universe, where the lifted function can only act on atoms and produce atoms as value. The nested-map is done in this universe, and the result is then optionally demoted to the usual Python universe.

Cong Ma
  • 10,692
  • 3
  • 31
  • 47