Reputation: 27
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.
Upvotes: 0
Views: 2207
Reputation: 366113
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] = …
.
Upvotes: 3
Reputation: 164823
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]]
Upvotes: 1