Reputation: 381
I have some nested lists and I want to be able to modify them having the indexes of where the modification would take place.
One example of such lists is:
l2 = ['Node_50',
['Node_48', 'Node_23', ['Node_12', 'Node_3'], ['Node_20']],
['Node_22', ['Node_44'], ['Node_7', 'Node_40']]
]
I then have a new list of elements and a list cointaing the indexes
lnew = ['Node_1', 'Node_40', 'Node_17']
indexes = [1, 3]
I would like to get a function that replaces the element of the list at the indexes given by the newlist of values. The function would have to do that (for this example):
l2[1][3] = lnew
The lists can have any number of nested lists so the length of indexes may change. The fucntion would need to work for any nested list and for any number of indexes.
Upvotes: 0
Views: 95
Reputation: 15537
I think that user8426627 has already given a great answer but if you prefer a functional style, you could do something like this:
>>> from functools import reduce
>>> from operator import getitem
>>> reduce(getitem, indexes[:-1], l2)[indexes[-1]] = lnew
>>> l2
['Node_50',
['Node_48', 'Node_23', ['Node_12', 'Node_3'], ['Node_1', 'Node_40', 'Node_17']],
['Node_22', ['Node_44'], ['Node_7', 'Node_40']]]
Upvotes: 2
Reputation: 943
shorter is :
l2 = ['Node_50',
['Node_48', 'Node_23', ['Node_12', 'Node_3'], ['Node_20']],
['Node_22', ['Node_44'], ['Node_7', 'Node_40']]
]
lnew = ['Node_1', 'Node_40', 'Node_17']
indexes = [1, 3]
def set_deep(root, indexes, value):
for x in indexes[:-1]:
root = root[x]
root[indexes[-1]] = value
set_deep(l2, indexes, lnew)
print(l2)
Thinking about it, the feature list[iterable] should be added to Python. I think actualy numpy supports list[list] notation?
Upvotes: 2
Reputation: 713
You do not need a function, just assign the new list to the desired position and it will replace the previous value.
l2 = ['Node_50',
['Node_48', 'Node_23', ['Node_12', 'Node_3'], ['Node_20']],
['Node_22', ['Node_44'], ['Node_7', 'Node_40']]
]
lnew = ['Node_1', 'Node_40', 'Node_17']
before
l2[1][3]
returns
['Node_20']
then replace it
l2[1][3] = lnew
after
l2[1][3]
returns
['Node_1', 'Node_40', 'Node_17']
This can also be done with a function
def myFUN(LIST, newLIST, indexes):
i,j = indexes
if i >= len(LIST):
print("list index (" + str(i) + ") out of range")
return
elif j >= len(LIST[i]):
print("list index (" + str(j) + ") out of range")
return
else:
LIST[i][j] = newLIST
return LIST
now
myFUN(l2, lnew, indexes)
returns
['Node_50', ['Node_48', 'Node_23', ['Node_12', 'Node_3'], ['Node_1', 'Node_40', 'Node_17']], ['Node_22', ['Node_44'], ['Node_7', 'Node_40']]]
but
myFUN(l2, lnew, (4,1))
returns
list index (4) out of range
and
myFUN(l2, lnew, (1,25))
returns
list index (25) out of range
Keep the original list unchanged
For python3
def myFUN(LIST, newLIST, indexes):
res = LIST.copy()
i,j = indexes
if i >= len(LIST):
print("list index (" + str(i) + ") out of range")
return
elif j >= len(LIST[i]):
print("list index (" + str(j) + ") out of range")
return
else:
res[i][j] = newLIST
return res
in python 2 use res = LIST[:]
or res=list(LIST)
. Now
myFUN(l2, lnew, indexes)
returns
['Node_50', ['Node_48', 'Node_23', ['Node_12', 'Node_3'], ['Node_1', 'Node_40', 'Node_17']], ['Node_22', ['Node_44'], ['Node_7', 'Node_40']]]
but l2 remains unaltered
l2
returns
['Node_50', ['Node_48', 'Node_23', ['Node_12', 'Node_3'], ['Node_20']], ['Node_22', ['Node_44'], ['Node_7', 'Node_40']]]
Upvotes: 0