Python Hierarchical嵌套列表中的元组列表

Python Hierarchical嵌套列表中的元组列表,python,list,nested,tuples,Python,List,Nested,Tuples,具有内部元素的外部列表,每个所述内部元素是 平面/嵌套列表。每个所述内部列表具有与前面的外部单元中的内部列表相匹配的嵌套结构。这意味着列表中的每个基元值要么对应于基元值,要么对应于下一个单元格列表中的列表(递归应用)。因此,每个内部列表的深度等于或超过前一单元格中元素的深度1 (请注意,第一个单元元素可以作为任何深度的嵌套列表开始) 上述示例: [ [[1, 2, [3, 4]], 1 ], [[3, [4, 5], [6, 7]], [5, 4]

具有内部元素的外部列表,每个所述内部元素是 平面/嵌套列表。每个所述内部列表具有与前面的外部单元中的内部列表相匹配的嵌套结构。这意味着列表中的每个基元值要么对应于基元值,要么对应于下一个单元格列表中的列表(递归应用)。因此,每个内部列表的深度等于或超过前一单元格中元素的深度1

(请注意,第一个单元元素可以作为任何深度的嵌套列表开始)

上述示例:

[
    [[1, 2,      [3, 4]], 1           ],
    [[3, [4, 5], [6, 7]], [5, 4]      ],   
    [[5, [6, 7], [8, 9]], [7, [8, 6]] ],
]
需要将嵌套列表展开为元组列表,其中每个值都与父值或对应的列表元素(如果父项是list,则保持顺序)组合。因此,对于上述示例列表,输出应为:

[
(1, 3, 5),
(2, 4, 6),
(2, 5, 7),
(3, 6, 8),
(4, 7, 9),
(1, 5, 7),
(1, 4, 8),
(1, 4, 6),
]
注意:此问题是对上一个问题的扩展,但与链接问题不同,此处所需的元组是平面的。

好的,这个问题如何:

x = [
    [[1, 2,      [3, 4]], 1           ],
    [[3, [4, 5], [6, 7]], [5, 4]      ],   
    [[5, [6, 7], [8, 9]], [7, [8, 6]] ],
]

from collections import defaultdict

def g(x):
    paths = defaultdict(lambda: [])

    def calculate_paths(item, counts):
        if type(item) is list:
            for i, el in enumerate(item):
                calculate_paths(el, counts + (i,))
        else:
            paths[counts].append(item)

    def recreate_values(k, initial_len, desired_len):
        if len(paths[k]) + initial_len == desired_len:
            yield paths[k]
        else:
            for ks in keysets:
                if len(ks) > len(k) and ks[0:len(k)] == k:
                    for ks1 in recreate_values(ks, initial_len + len(paths[k]), desired_len):
                        yield paths[k] + ks1

    for lst in x:
        calculate_paths(lst, (0,))
    keysets = sorted(list(paths.keys()))
    for k in keysets:
        yield from recreate_values(k, 0, len(x))


>>> import pprint
>>> pprint.pprint(list(g(x)))
[[1, 3, 5],
 [2, 4, 6],
 [2, 5, 7],
 [3, 6, 8],
 [4, 7, 9],
 [1, 5, 7],
 [1, 4, 8],
 [1, 4, 6]]
其工作原理是为结构中的每个数字创建一个“路径”,这是一个元组,用于标识它如何适合其特定行


(最初尝试):

如果它总是三个级别,那么像这样的东西

def listify(lst):
    max_len = max(len(item) if type(item) is list else 1 for item in lst)
    yield from zip(*[item if type(item) is list else [item] * max_len for item in lst])


def f():
    for i in listify(x):
        for j in listify(i):
            for k in listify(j):
                yield k

>>> list(f())

这是一个需要解决的问题:-)

我确实设法得到了不同级别的解决方案。然而,我做了一个假设:

  • 输入的最后一列是指向其他列的指针
如果这不是问题,那么以下解决方案可以正常工作:-)


我知道这不是一个很好的解决方案,可以进一步优化。我在想一个比这个更好的算法。如果得到更好的解决方案,将更新:-)

我第一次尝试使用2d矩阵解决此问题,但结果表明,迭代最后一行,将其上面的列段分割,更简单:

def unfold(ldata):
    ''' 
    ldata: list of hierarchical lists.
    technique: repeatedly flatten bottom row one level at a time, unpacking lists or
    adding repeats in the column above at the same time. 
    convention: n=1 are primitives, n>=2 are lists.
    '''

    has_lists = True
    while has_lists:
        has_lists = False 
        for i, elm in enumerate(ldata[-1]):
            if type(elm) is list:
                has_lists = True
                ldata[-1][i:i+1] = ldata[-1][i] # unpack
                for k in range(0, len(ldata)-1): # over corresponding items in above column
                    if type(ldata[k][i]) is list:
                        ldata[k][i:i+1] = ldata[k][i] # unpack
                    else:
                        ldata[k][i:i+1] = [ldata[k][i]]*len(elm) # add repeats
    return list(zip(*ldata))            

x = [
    [[1, 2,      [3, 4]], 1           ],
    [[3, [4, 5], [6, 7]], [5, 4]      ],   
    [[5, [6, 7], [8, 9]], [7, [8, 6]] ],
]

from pprint import pprint
pprint(unfold(x))

>>>
[(1, 3, 5),
 (2, 4, 6),
 (2, 5, 7),
 (3, 6, 8),
 (4, 7, 9),
 (1, 5, 7),
 (1, 4, 8),
 (1, 4, 6)]

当数据处于复杂的结构中时,像这样,您应该修复源代码:(为什么
[(2,4,6)、(2,5,7)]
,而不是
[(2,4,5],[6,7])]
?@khajvah:所需的输出是扁平元组,-这与链接问题不同,我将进行编辑以澄清这一点。如果列表有父基元,列表中的每个值都与父基元结合,如果列表有父基元列表,则相应的值也会结合。@thefourtheye:请指出问题。关于问题本身的一个注释f、 我想,你的名声省去了这个问题。如果你是一个新人,你会看到很多反对票和评论,比如:“你尝试了什么吗?”,“我们不做作业”,“尝试一些东西,然后问我们你是否发现了问题。”…不总是三个级别。一般列表。
def unfold(ldata):
    ''' 
    ldata: list of hierarchical lists.
    technique: repeatedly flatten bottom row one level at a time, unpacking lists or
    adding repeats in the column above at the same time. 
    convention: n=1 are primitives, n>=2 are lists.
    '''

    has_lists = True
    while has_lists:
        has_lists = False 
        for i, elm in enumerate(ldata[-1]):
            if type(elm) is list:
                has_lists = True
                ldata[-1][i:i+1] = ldata[-1][i] # unpack
                for k in range(0, len(ldata)-1): # over corresponding items in above column
                    if type(ldata[k][i]) is list:
                        ldata[k][i:i+1] = ldata[k][i] # unpack
                    else:
                        ldata[k][i:i+1] = [ldata[k][i]]*len(elm) # add repeats
    return list(zip(*ldata))            

x = [
    [[1, 2,      [3, 4]], 1           ],
    [[3, [4, 5], [6, 7]], [5, 4]      ],   
    [[5, [6, 7], [8, 9]], [7, [8, 6]] ],
]

from pprint import pprint
pprint(unfold(x))

>>>
[(1, 3, 5),
 (2, 4, 6),
 (2, 5, 7),
 (3, 6, 8),
 (4, 7, 9),
 (1, 5, 7),
 (1, 4, 8),
 (1, 4, 6)]