slicing - Buscar índice de elemento anidado en python
slice python 3 (3)
He estado trabajando con algunas matrices relativamente complejas, como:
array = [ "1", 2, ["4", "5", ("a", "b")], ("c", "d")]
y estaba buscando una manera de encontrar un elemento y recuperar es "índice" (¿Está bien referirse a la ubicación del elemento como "a" - que está dentro de una Tupla como índice en el mismo nivel que la matriz?)
Ahora mi primer pensamiento fue utilizar algo así como una función auxiliar simple como:
def myindex(nestedlist, item):
for i in nestedlist:
if item in i:
index = []
index.append(i)
index.append(i.index(item))
return index
Pero estoy seguro de que puede adivinar que dicha función no servirá de mucho, sobre todo porque no sé de antemano cuántos niveles podría tener la matriz, y qué podría contener cada nivel (en términos de tipo de datos / estructura )
Cualquier sugerencia en la dirección correcta sería muy apreciada.
Llego un poco tarde a la fiesta, pero pasé varios minutos en ella, así que siento que debería publicarse de todos modos :)
def getindex(container, target, chain=None):
if chain is None: chain = list()
for idx, item in enumerate(container):
if item == target:
return chain + [idx]
if isinstance(item, collections.Iterable) and not isinstance(item, str):
# this should be ... not isinstance(item, basestring) in python2.x
result = getindex(item, target, chain + [idx])
if result:
return result
return None
Lo que quieres es algo así como:
def myindex(lst, target):
for index, item in enumerate(lst):
if item == target:
return [index]
if isinstance(item, (list, tuple)):
path = myindex(item, target)
if path:
return [index] + path
return []
Recursivo, esto tratará con profundidad de anidamiento arbitraria (hasta el límite de recursión).
Para su array
ejemplo, obtengo:
>>> myindex(array, "a")
[2, 2, 0]
Como alude Adán en los comentarios, la comprobación explícita de los tipos de instancia no es muy pitonica. Una alternativa tipo pato , "más fácil de pedir perdón que permiso" sería:
def myindex(lst, target):
for index, item in enumerate(lst):
if item == target:
return [index]
if isinstance(item, str): # or ''basestring'' in 2.x
return []
try:
path = myindex(item, target)
except TypeError:
pass
else:
if path:
return [index] + path
return []
El manejo específico de cadenas es necesario ya que incluso una cadena vacía se puede iterar, lo que causa recursiones sin fin.
array = ["1", 2, ["4", "5", ("a", "b")], ("c", "d")]
def find_index(array, item, index=None):
if not index:
index = []
try:
i = array.index(item)
except:
for new_array in array:
if hasattr(new_array, ''__iter__''):
i = find_index(new_array, item, index+[array.index(new_array)])
if i:
return i
else:
return index + [i]
return None
Esto da:
>>> find_index(array, 1)
>>> find_index(array, "1")
[0]
>>> find_index(array, 2)
[1]
>>> find_index(array, "4")
[2, 0]