简体   繁体   English

用计数来替换嵌套列表中的元素

[英]substitute elements in the nested list by their counting numbers

I have a nested list: 我有一个嵌套列表:

x=[[[0, 1, 2], [0, 1, 2]], [[0, 1], [0, 1, 2]], [[0]], [[0, 1], [0, 1, 2, 3, 4]]]

Now, the goal is to get a nested list with the same structure but with elements replaced by their "global" counting numbers. 现在,目标是获得具有相同结构但元素被其“全局”计数数字替换的嵌套列表。 So, the desired output should look like this: 因此,所需的输出应如下所示:

y=[[[0, 1, 2], [3, 4, 5]], [[6, 7], [8, 9, 10]], [[11]], [[12, 13], [14, 15, 16, 17, 18]]]

I fight with it for the last couple of hours but without success. 我在最后几个小时内与之抗争,但没有成功。

Ideally, I'd like to have a universal solution being able to work with an arbitrary depth of nesting. 理想情况下,我希望有一个通用的解决方案,能够处理任意深度的嵌套。

Any help would be very much appreciated. 任何帮助将不胜感激。 Thank you in advance! 先感谢您!

Here's a recursive solution that does the replacement in-place and relies on the type of the element being replaced. 这是一个递归解决方案,它就地进行替换并依赖于要替换的元素的type The idea is to keep track of the "global counter" and pass it into the recursive calls so that it knows what to replace elements with: 这个想法是跟踪“全局计数器”并将其传递给递归调用,以便它知道用以下内容替换元素:

x = [[[0, 1, 2], [0, 1, 2]], [[0, 1], [0, 1, 2]], [[0]], [[0, 1], [0, 1, 2, 3, 4]]]

def replace(lst, i):
    for j in range(len(lst)):
        if isinstance(lst[j], list):
            lst[j], i = replace(lst[j], i)
        else:
            lst[j] = i
        i += 1
    return lst, i - 1

replace(x, 0)
print(x)
# [[[0, 1, 2], [3, 4, 5]], [[6, 7], [8, 9, 10]], [[11]], [[12, 13], [14, 15, 16, 17, 18]]]

Here's another recursive solution. 这是另一个递归解决方案。 It uses itertools.count and builds a new list. 它使用itertools.count并构建一个新列表。 Personally, I like to avoid integer indexing when possible for readability. 就个人而言,我希望尽可能避免整数索引以提高可读性。

from itertools import count

def structured_enumerate(lst, counter=None):
    'enumerate elements in nested list, preserve structure'
    result = []
    if counter is None:
        counter = count()

    for x in lst:
        if isinstance(x, list):
            result.append(structured_enumerate(x, counter))
        else:
            result.append(next(counter))
    return result

Demo: 演示:

>>> x = [[[0, 1, 2], [0, 1, 2]], [[0, 1], [0, 1, 2]], [[0]], [[0, 1], [0, 1, 2, 3, 4]]]
>>> structured_enumerate(x)
[[[0, 1, 2], [3, 4, 5]],
 [[6, 7], [8, 9, 10]],
 [[11]],
 [[12, 13], [14, 15, 16, 17, 18]]]

~edit~ 〜编辑〜

Here's an attempt at a generic solution that works with any iterable, indexable or not, where you can specifiy iterable types to exclude from iteration. 这是一种尝试与任何可迭代,可索引或不可索引的通用解决方案的尝试,您可以在其中指定可迭代类型以将其排除在迭代之外。

from itertools import count

def structured_enumerate(iterable, dontiter=(str,), counter=None):
    'enumerate elements in nested iterable, preserve structure'
    result = []
    if counter is None:
        counter = count()

    for x in iterable:
        # check if x should be iterated
        try:
            iter(x)
            is_iterable = True
        except TypeError:
            is_iterable = False

        # strings of length zero and one are a special case
        if isinstance(x, str) and len(x) < 2:
            is_iterable = False

        if is_iterable and not isinstance(x, dontiter):
            subresult = structured_enumerate(x, dontiter, counter)
            result.append(subresult)
        else:
            result.append(next(counter))

    return result

Demo: 演示:

>>> fuzzy = [{0, 0}, '000', [0, [0, 0]], (0,0), 0]
>>> structured_enumerate(fuzzy)
[[0, 1], 2, [3, [4, 5]], [6, 7], 8]
>>> structured_enumerate(fuzzy, dontiter=())
[[0, 1], [2, 3, 4], [5, [6, 7]], [8, 9], 10]
>>> structured_enumerate(fuzzy, dontiter=(tuple, set))
[0, [1, 2, 3], [4, [5, 6]], 7, 8]

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM