在Python中查找嵌套项的索引

2 投票
3 回答
2654 浏览
提问于 2025-04-18 11:06

我最近在处理一些比较复杂的数组,比如:

array = [ "1", 2, ["4", "5", ("a", "b")], ("c", "d")]

我想找一个特定的项目,并获取它的“索引”(我可以把像“a”这样的项目在元组中的位置称为索引吗?它和数组的索引是同一级别的吗?)

我最初想到的是使用一个简单的辅助函数,比如:

def myindex(nestedlist, item):
    for i in nestedlist:
        if item in i:
         index = []
         index.append(i)
         index.append(i.index(item))
         return index

但你们肯定能猜到,这样的函数没什么用,特别是因为我不知道数组可能有多少层,以及每一层可能包含什么(在数据类型或结构方面)

如果能给我一些正确的方向建议,我会非常感激!

3 个回答

0

我来得有点晚,不过我花了几分钟在这个问题上,所以我觉得还是应该分享一下 :)

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
1

这里有一个数组,里面包含了不同类型的数据。这个数组叫做 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

这就是你会看到的结果:

>>> find_index(array, 1)
>>> find_index(array, "1")
[0]
>>> find_index(array, 2)
[1]
>>> find_index(array, "4")
[2, 0]
7

你想要的东西大概是这样的:

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 []

因为这是递归的,所以它可以处理任意深度的嵌套(直到达到递归限制)。

对于你的例子 array,我得到的是:

>>> myindex(array, "a")
[2, 2, 0]

正如亚当在评论中提到的,明确检查实例类型并不是很符合Python的风格。一个更“Pythonic”的方式是使用鸭子类型“宁可请求原谅,也不要请求许可”的方式:

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 []

特别处理字符串是必要的,因为即使是空字符串也可以被迭代,这会导致无限递归。

撰写回答