RError.com

RError.com Logo RError.com Logo

RError.com Navigation

  • 主页

Mobile menu

Close
  • 主页
  • 系统&网络
    • 热门问题
    • 最新问题
    • 标签
  • Ubuntu
    • 热门问题
    • 最新问题
    • 标签
  • 帮助
主页 / 问题 / 1526922
Accepted
Aleksandr Bogatyrev
Aleksandr Bogatyrev
Asked:2023-06-22 07:44:03 +0000 UTC2023-06-22 07:44:03 +0000 UTC 2023-06-22 07:44:03 +0000 UTC

Python获取任意嵌套深度的元素索引

  • 772

您能否告诉我是否有选项可以获取嵌套深度未知的元素的索引,或者是否有一个变量可以指向此类元素的路径?

我正在解决一个非常需要“当场”进行更改的问题,尽管没有人禁止用更改后的结果替换原始源。

假设我们有一个列表:

lst = [
        'el1',
        ['el2', 15, 'text'],
        ['el3', '2.6', ['el4', ['el5']]],
        'el6'
     ]

从这个列表中,我们想要获取元素的路径'el5'以将其转换为例如元组。

我对 python 的基本了解表明,我们可以创建一个临时变量,并通过搜索底层列表,创建指向感兴趣元素的链接。

我可能是错的,但在这种情况下,我们将获得包含所需元素的本地片段的链接。但对于操作,我们需要使用索引的完整路径来引用源。否则,原始源中的转换将不会发生。

例如,当您沿着源移动时,您可以以索引列表的形式获取路径:

def find_elem(lst: list, elem: any) -> list[int] | None:
    '''получаем путь до искомого элемента в виде списка индексов'''
    for i, el in enumerate(lst):
        if isinstance(el, (list, tuple)):
            returned = find_elem(el, elem)
            if returned != None:    #   проверяем был ли во вложенном списке искомый элемент
                return [i, ] + returned
        elif el == elem:
            return [i, ]
    return None #   элемент в переданной коллекции не нашелся


print(find_elem(lst, 'el5'))   #   вернет путь виде списка [2, 2, 1, 0]

问题是如何将这个列表转换为 needed_elem = lst[2][2][1][0]

PS 我把这个函数写在膝盖上只是为了展示问题的本质。

UPD。我附上了应用算法的结果以及所需元素的源和本地化之旅。结果,原始来源仍保持其原始形式......

needed_elem = find_elem(lst, 'text')   №   [1, 2]
needed_addr = lst[1][2]
needed_addr = ['text', 'new text']
print(lst)    #    ['el1', ['el2', 15, 'text'], ['el3', '2.6', ['el4', ['el5']]], 'el6']

lst[1][2] = ['text', 'new text']
print(lst)    #    ['el1', ['el2', 15, ['text', 'new text']], ['el3', '2.6', ['el4', ['el5']]], 'el6']

从上面的例子可以看出,只有第二版的申诉才导致了变化。

python
  • 3 3 个回答
  • 105 Views

3 个回答

  • Voted
  1. strawdog
    2023-06-22T16:48:19Z2023-06-22T16:48:19Z

    创建一个新的列表列表,您将在其中递归地放置旧列表中的所有元素,并用所需的元素替换所需的元素。这是列表列表的示例,您需要使用元组来完成它:

    lst = [
            'el1',
            ['el2', 15, 'text'],
            ['el3', '2.6', ['el4', ['el5']]],
            'el6'
         ]
    
    def replace_items(l, a, b):
        for i, item in enumerate(l):
            if (type(l[i]) == list):
                l[i] = replace_items(l[i], a=a, b=b)
            else:
                if l[i] == a:
                       l[i] = b
        return l
    
    new = replace_items(lst, a='el5', b=0)
    print(new)
    

    ['el1', ['el2', 15, '文本'], ['el3', '2.6', ['el4', [0]]], 'el6']

    更新

    如果您只是想知道如何获取给定嵌套索引列表的元素,那么它的实现如下:

    from functools import reduce 
    from operator import getitem
    lst = [
            'el1',
            ['el2', 15, 'text'],
            ['el3', '2.6', ['el4', ['el5']]],
            'el6'
         ]
    idx = [2, 2, 1, 0]
    res = reduce(getitem, idx, lst)
    print(res)
    

    埃尔5

    但是,我不知道以这种方式更改列表项的值的合法方法。

    更新2

    正如这里正确建议的那样,获取对象就足够了 - 具有所需元素和该元素索引的最嵌套列表,然后就可以更改值:

    idx = [2, 2, 1, 0]
    inner_lst = reduce(getitem, idx[:-1], lst)
    inner_lst[idx[-1]] = "lol"
    print(lst)
    

    ['el1', ['el2', 15, '文本'], ['el3', '2.6', ['el4', ['lol']]], 'el6']

    • 2
  2. insolor
    2023-06-22T18:09:47Z2023-06-22T18:09:47Z

    当您从列表(包括深度嵌套列表)中获取元素时,您确实获得了引用,但不是指向嵌套列表中的位置,而是指向值本身。此链接无法替换列表中的元素。你只能改变一个对象(如果它是可变的),那么它的改变将反映在原始结构中。

    要更改嵌套列表内的值,您已经需要列表本身(元素所在的嵌套列表)和其中的索引,即有条件地需要两个“坐标”。然后就可以通过替换找到的索引处的值来改变列表:

    from typing import Any
    
    
    def find_elem(lst: list, elem: Any) -> tuple[list, int] | None:
        for i, el in enumerate(lst):
            if el == elem:
                return lst, i
            elif isinstance(el, list):
                result = find_elem(el, elem)
                if result is not None:
                    return result
    
        return None
    
    
    lst = ['el1', ['el2', 15, 'text'], ['el3', '2.6', ['el4', ['el5']]], 'el6']
    
    position = find_elem(lst, 'el5')
    assert position is not None, "Значение не найдено"
    
    print(lst)
    position[0][position[1]] = ['text', 'new text']
    print(lst)
    
    # Для лучшей читаемости строку position[0][position[1]] = ... можно переписать так
    inner_list, i = position
    inner_list[i] = ['text', 'new text']
    

    结论:

    ['el1', ['el2', 15, 'text'], ['el3', '2.6', ['el4', ['el5']]], 'el6']
    ['el1', ['el2', 15, 'text'], ['el3', '2.6', ['el4', [['text', 'new text']]]], 'el6']
    
    • 2
  3. Best Answer
    Stanislav Volodarskiy
    2023-06-23T03:17:25Z2023-06-23T03:17:25Z

    该问题已经有两个正确答案。除了解决问题的可能设计之外,我几乎没有什么可补充的。

    有两种解决方案。第一个很简单。第二个是语法糖。

    一个简单的解决方案

    locate(list_, value)value- 返回列表中所有出现的值的生成器list_。列表本身及其所有子列表都是递归查看的。

    replace_first(list_, old, new)将第一个值old(如果有)替换为new。

    replace_all(list_, old, new)将所有值替换old为new.

    def locate(list_, value):
        for i, v in enumerate(list_):
            if v == value:
                yield list_, i
            if isinstance(v, list):
                yield from locate(v, value)
    
    
    def replace_first(list_, old, new):
        for lst, i in locate(list_, old):
            lst[i] = new
            break
    
    
    def replace_all(list_, old, new):
        for lst, i in locate(list_, old):
            lst[i] = new
    
    
    lst = [
        'el1',
        ['el2', 15, 'text'],
        ['el3', '2.6', ['el4', ['el5']]],
        'el6'
    ]
    
    print(*locate(lst, 'text'))
    
    print(lst)
    replace_all(lst, 'text', ['text', 'new text'])
    print(lst)
    
    $ python replace.py
    (['el2', 15, 'text'], 2)
    ['el1', ['el2', 15, 'text'], ['el3', '2.6', ['el4', ['el5']]], 'el6']
    ['el1', ['el2', 15, ['text', 'new text']], ['el3', '2.6', ['el4', ['el5']]], 'el6']
    

    多索引解决方案

    该类NestedList包装一个列表并提供如下语法:

    nlst = NestedList(lst)  # создание обёртки
    
    print(nlst[[1, 2]])     # обращение ко второму индексу
                            # первого подсписка списка
    
    nlst[[1, 2]] = value    # изменение этого же элемента
    
    nlst.locate(value)      # перебирает все мультииндексы
                            # значения value
    
    class NestedList:
        def __init__(self, list_):
            self._list = list_
    
        def __getitem__(self, index):
            v = self._list
            for i in index:
                v = v[i]
            return v
    
        def __setitem__(self, index, value):
            v = self._list
            for i in index[:-1]:
                v = v[i]
            v[index[-1]] = value
    
        def locate(self, value):
    
            def locate(list_, stack):
                for i, v in enumerate(list_):
                    top = stack, i
                    if v == value:
                        index = []
                        node = top
                        while node is not None:
                            index.append(node[1])
                            node = node[0]
                        yield index[::-1]
                    if isinstance(v, list):
                        yield from locate(v, top)
    
            yield from locate(self._list, None)
    
    
    
    lst = [
        'el1',
        ['el2', 15, 'text'],
        ['el3', '2.6', ['el4', ['el5']]],
        'el6'
    ]
    
    nlst = NestedList(lst)
    
    print('list =', lst)
    i = next(nlst.locate('text'))
    print('i =', i)
    print('nlst[i] =', nlst[i])
    nlst[i] = ['text', 'new text']
    print('nlst[i] =', nlst[i])
    print('list =', lst)
    
    $ python replace.py
    list = ['el1', ['el2', 15, 'text'], ['el3', '2.6', ['el4', ['el5']]], 'el6']
    i = [1, 2]
    nlst[i] = text
    nlst[i] = ['text', 'new text']
    list = ['el1', ['el2', 15, ['text', 'new text']], ['el3', '2.6', ['el4', ['el5']]], 'el6']
    
    • 2

相关问题

  • 是否可以以某种方式自定义 QTabWidget?

  • telebot.anihelper.ApiException 错误

  • Python。检查一个数字是否是 3 的幂。输出 无

  • 解析多个响应

  • 交换两个数组的元素,以便它们的新内容也反转

Sidebar

Stats

  • 问题 10021
  • Answers 30001
  • 最佳答案 8000
  • 用户 6900
  • 常问
  • 回答
  • Marko Smith

    我看不懂措辞

    • 1 个回答
  • Marko Smith

    请求的模块“del”不提供名为“default”的导出

    • 3 个回答
  • Marko Smith

    "!+tab" 在 HTML 的 vs 代码中不起作用

    • 5 个回答
  • Marko Smith

    我正在尝试解决“猜词”的问题。Python

    • 2 个回答
  • Marko Smith

    可以使用哪些命令将当前指针移动到指定的提交而不更改工作目录中的文件?

    • 1 个回答
  • Marko Smith

    Python解析野莓

    • 1 个回答
  • Marko Smith

    问题:“警告:检查最新版本的 pip 时出错。”

    • 2 个回答
  • Marko Smith

    帮助编写一个用值填充变量的循环。解决这个问题

    • 2 个回答
  • Marko Smith

    尽管依赖数组为空,但在渲染上调用了 2 次 useEffect

    • 2 个回答
  • Marko Smith

    数据不通过 Telegram.WebApp.sendData 发送

    • 1 个回答
  • Martin Hope
    Alexandr_TT 2020年新年大赛! 2020-12-20 18:20:21 +0000 UTC
  • Martin Hope
    Alexandr_TT 圣诞树动画 2020-12-23 00:38:08 +0000 UTC
  • Martin Hope
    Air 究竟是什么标识了网站访问者? 2020-11-03 15:49:20 +0000 UTC
  • Martin Hope
    Qwertiy 号码显示 9223372036854775807 2020-07-11 18:16:49 +0000 UTC
  • Martin Hope
    user216109 如何为黑客设下陷阱,或充分击退攻击? 2020-05-10 02:22:52 +0000 UTC
  • Martin Hope
    Qwertiy 并变成3个无穷大 2020-11-06 07:15:57 +0000 UTC
  • Martin Hope
    koks_rs 什么是样板代码? 2020-10-27 15:43:19 +0000 UTC
  • Martin Hope
    Sirop4ik 向 git 提交发布的正确方法是什么? 2020-10-05 00:02:00 +0000 UTC
  • Martin Hope
    faoxis 为什么在这么多示例中函数都称为 foo? 2020-08-15 04:42:49 +0000 UTC
  • Martin Hope
    Pavel Mayorov 如何从事件或回调函数中返回值?或者至少等他们完成。 2020-08-11 16:49:28 +0000 UTC

热门标签

javascript python java php c# c++ html android jquery mysql

Explore

  • 主页
  • 问题
    • 热门问题
    • 最新问题
  • 标签
  • 帮助

Footer

RError.com

关于我们

  • 关于我们
  • 联系我们

Legal Stuff

  • Privacy Policy

帮助

© 2023 RError.com All Rights Reserve   沪ICP备12040472号-5