0

I am still fairly new to Python. I have a list that includes numbers and lists of numbers:

list1 = [[3,3,2,2,1,1], 5, [2, 1], 2, [6,2,8]]

I have a function that will loop inside and determine if the item is a number or a list. If a list is detected, it will loop inside the inner list, otherwise continue.

def searchlist(ls):
    global list1
    for element in ls:
        if isinstance(element,list):
            searchlist(element)
        elif (element == 2):
            element += 3
            list1[?][?] = element

The code obviously doesn't work but I'm looking for a way I can get the values of [?] for the actual indices of 2 in the list. So in the previous example, the following items will be replaced:

list1[0][2], list1[0][3], list1[2][0], list1[3], and list1[4][1]

I want this function to be able to change the value for the global variable (list1). So for example after calling the function searchlist on the list list1, the value of list1 should be:

list1 = [[3,3,5,5,1,1], 5, [5, 1], 5, [6,5,8]]

And I want to use this function on any list in the future, so the sizes aren't constant.

2
  • oh by the way, I'm calling the function again after each change for now. I will try to implement a better way in the future, but suggestions are also welcome Commented Jul 17, 2018 at 18:47
  • If you just have a handful of changes—add 3 if it's == 2, subtract 4 if it's == 4, etc.—just add a couple more elif`s. If you have a bunch of changes, try to come up with a way to represent them as a dict. See here on repl.it for some progressively more complicated but flexible things you could do. Commented Jul 17, 2018 at 20:01

2 Answers 2

3

Since you already have a recursive function, you don't need to index the top-level nested list from the top, you just need to index the current ls parameter.

For example, on the first match, ls is the same list as list1[0], so ls[2] = … does the same thing as list1[0][2] = ….

So:

def searchlist(ls):
    for i, element in enumerate(ls):
        if isinstance(element,list):
            searchlist(element)
        elif (element == 2):
            element += 3
            ls[i] = element

If you really did want to get a whole sequence of indexes, you'd need to build that up recursively, and then apply it either recursively or in a loop. Something like this:

def searchlist(ls, *, _top=None, _indexes=()):
    if _top is None: _top = ls

    for i, element in enumerate(ls):
        if isinstance(element,list):
            searchlist(element, _top=_top, _indexes=_indexes + (i,))
        elif (element == 2):
            element += 3
            node = _top
            for index in _indexes:
                node = node[index]
            node[i] = element

To understand this, notice that a multiple-indexed list as an assignment target is a little weird:

lst[a][b][c] = d

What this actually does is something like this:

_tmp = lst[a][b]
_tmp.__setitem__(c, d)

In other words, the very last index is special, but all of the indices before it are treated as in a normal expression.

So, that's why looping over node = node[index] for all indexes but the last one gives us the right thing to use with node[i] = ….

Sign up to request clarification or add additional context in comments.

2 Comments

Thank you so much, both of them worked. I'd rather go with the first approach since it seemed simpler to me. Is there any way to replace the value of the whole inner list rather than just the element inside it?
@Omar Yes, just slice-assign the whole thing, like ls[:] = [1, 2] and now the inner list contains just 1 and 2.
1

You don't need global. Here's a simple algorithm specific to the structure of your input:

list1 = [[3,3,2,2,1,1], 5, [2, 1], 2, [6,2,8]]

def changer(L, in_val, out_val):
    for idx, item in enumerate(L):
        if not isinstance(item, list):
            if item == in_val:
                L[idx] = out_val
        else:
            L[idx] = [i if i != in_val else out_val for i in item]
    return L

changer(list1, 2, 5)

[[3, 3, 5, 5, 1, 1], 5, [5, 1], 5, [6, 5, 8]]

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.