Reputation: 18622
I have a list of items they may or may not be arbitrarily nested. I would like to replace one of the lists' elements. Either way (nested or not), I have the element's index location stored in another list.
Here's a nested list example where I would like to replace 'xyz'
with something else, say 123
. I have the location of 'xyz'
stored in loc
:
find='xyz'
replace=123
nested=[['abc',1],['xyz',2]]
print(loc) # [1,0]
Using loc
how can I substitute 'xyz'
for 123
?
Here is an unnested example where I would like to do the same substitution:
unnested=['abc','xyz']
print(loc) # [1]
If loc
only has one element then you can simply do:
*nest,element=loc
if not nest:
unnested[element]=replace
else: pass # need help with this part
Is there something flexible enough to handle both cases?
Upvotes: 3
Views: 2077
Reputation: 28596
This does the same as the other answer, just walks the path in a functional fashion:
reduce(getitem, loc[:-1], nested)[loc[-1]] = replace
In Python 3 you'll need to import reduce
from functools
. And getitem
is from the operator
module. If you just have lists, you could use list.__getitem__
instead.
Explanation: reduce
starts with nested
and replaces it with getitem(thecurrentvalue, i)
for each value i
in loc[:-1]
. So for example if loc
is [2, 4, 1, 3]
then you get getitem(getitem(getitem(nested, 2), 4), 1)
. Which is the same as nested[2][4][1]
.
Upvotes: 3
Reputation: 11443
if you just have lists that has tuple or single element, we can first detect if a list has tuples and apply lambda function to replace elements as desired.
If the list has different types of tuples, we will need to add additional logic to recognize that.
find='xyz'
replace=123
mylist1=[('abc',1),('xyz',2)] # nests could be tuples or lists
mylist2=['abc','xyz']
replace_this = '123'
for mylist in mylist1,mylist2:
for x in mylist:
if (x[0],x[1]) in mylist:
modified = map(lambda (x, y): (x,y) if x!=find else (replace_this,y) ,mylist)
break
else:
modified = map(lambda x: x if x!=find else replace_this ,mylist)
break
print "modified list=", modified
output:
Python 2.7.9 (default, Dec 10 2014, 12:24:55) [MSC v.1500 32 bit (Intel)] on win32
Type "copyright", "credits" or "license()" for more information.
>>> ================================ RESTART ================================
>>>
modified list= [('abc', 1), ('123', 2)]
modified list= ['abc', '123']
>>>
Upvotes: 0
Reputation: 21453
ok so given loc = [0,1]
you would want to preform the operation:
thing[0][1] = replace
or given loc = [1]
you would preform
thing[1] = replace
or if we had overly complicated data and loc = [0,1,2,3,4,5,6,7]
you would want:
thing[0][1][2][3][4][5][6][7] = replace
In any case we first need to look up each layer before the last element which we can do in a for loop like this:
*nest,element=[0,1,2,3,4,5,6,7]
layer = thing #start with the original object
for i in nest:
layer = layer[i] #get an element from this layer
#now layer == thing[0][1][2][3][4][5][6]
layer[element] = replace
This also works when there is only one item in loc
since in that case the for loop is iterating over an empty sequence so there is no need to treat that case seperately
Upvotes: 3