I have some code that generates a list that looks something like this:
chrs = [[["a",["b","c"]],["d","e"],"f"],["g",[["h","i"],"j"]]]
Now I need to find a specific value in some kind of list like this.
I wrote some code to do this, but it seems to get stuck in an infinite loop:
def locate_value(v,chrs): #
checked=[[]] # Set up the values
index_list=[] #
inside=0 #
cur=[0,0] #
#
while True: #
if chrs[cur[0]] == v: # If found, end the loop and return the index_list
return index_list #
#
if type(chrs[cur[0]]) != list: # If the current is not a list, skip this one
checked[inside].append(cur[0]) #
index_list = [] #
#
else: #
try: #
if cur[0] in gone[inside]: # If the current has been done before, skip it
cur[0] = 1 #
#
else: # And if not, move 1 space deeper
checked.append([]) #
index_list.append(cur[0]) #
cur[1] = cur[0] #
cur[0] = 0 #
inside = 1 #
#
except IndexError: # And if a sublist is fully checked, block it too
checked[inside].append(cur[1]) #
print(locate_value("e",[[["a",["b","c"]],["d","e"],"f"],["g",[["h","i"],"j"]]]))
Editing me just realised how bad this code is
In this example, the function locate_value
should return [0, 1, 1]
, as list[0][1][1]
is "e"
But when I run this, I get stuck in an infinite loop Can anyone tell me what is wrong, and maybe give me some code that actually works for once.
The list is made with user input, so I have no idea how deep it is.
Though a python-3 only solution is fine, I would prefer one that supports python-2, too.
CodePudding user response:
Use a recursion function:
def locate_value(v, chrs, idx=[]):
for j, i in enumerate(chrs):
if isinstance(i, list):
yield from find(v, i, idx [j])
elif i == v:
yield idx [j]
Another version to keep your original signature function:
def locate_value(v, chrs):
for j, i in enumerate(chrs):
if isinstance(i, list):
yield from ([j, *idx] for idx in locate_value(v, i))
elif i == v:
yield [j]
Output:
>>> list(locate_value('e', chrs, []))
[[0, 1, 1]]
# case of multiple 'e'
# chrs = [[["a",["b","c"]],["d","e"],"f"],["g",[["h","e"],"j"]]]
>>> list(locate_value('e', chrs))
[[0, 1, 1], [1, 1, 0, 1]]
Greatly improved by @tobias_k
CodePudding user response:
The following will work:
def locate_value(v, chrs):
if v == chrs:
return []
if not isinstance(chrs, list):
raise IndexError
for i, c in enumerate(chrs):
try:
return [i] locate_value(v, c)
except IndexError:
pass
raise IndexError
locate_value("e", [[["a",["b","c"]],["d","e"],"f"],["g",[["h","i"],"j"]]])
# [0, 1, 1]
Note that str
objects are iterables themselves, so recursively keeping iterating their elements (strings yet again) will never end.