首页 > 解决方案 > 如何使用 zip 连接深层嵌套列表的最里面的元素

问题描述

假设我有以下包含列表的列表:

samples = [
    # First sample
    [
        # Think 'x' as in input variable in ML
        [
            ['A','E'], # Data
            ['B','F']  # Metadata
        ],
        # Think 'y' as in target variable in ML
        [
            ['C','G'], # Data
            ['D','H'], # Metadata
        ]
    ],
    # Second sample
    [
        [
            ['1'],
            ['2']
        ],
        [
            ['3'],
            ['4']
        ]
    ]
]

我追求的输出如下所示:

>>> samples
[
    ['A','E','1'], # x.data
    ['B','F','2'], # x.metadata
    ['C','G','3'], # y.data
    ['D','H','4']  # y.metadata
]

我的问题是,是否存在一种利用 Pythonzip函数的方法,也许还有一些列表推导来实现这一点?

我已经搜索了一些解决方案,但例如thisthis处理使用zip来处理不同的列表,而不是内部列表。

实现这一点的一种方法很可能只是对这样的样本进行简单的迭代:

x,x_len,y,y_len=[],[],[],[]

for sample in samples:
    x.append(sample[0][0])
    x_len.append(sample[0][1])
    y.append(sample[1][0])
    y_len.append(sample[1][1])

samples = [
    x,
    x_len,
    y,
    y_len
]

我仍然很好奇是否存在一种方法来利用zip循环for样本及其嵌套列表。

请注意,datametadata的长度可能因样本而异。

标签: pythonlistnestediterationlist-comprehension

解决方案


IIUC,一种方法是用来itertools.chain展平 的结果zip(samples)

from itertools import chain

new_samples = [
    list(chain.from_iterable(y)) for y in zip(
        *((chain.from_iterable(*x)) for x in zip(samples))
    )
]

print(new_samples)
#[['A', 'E', '1'], ['B', 'F', '2'], ['C', 'G', '3'], ['D', 'H', '4']]

一步一步的解释

zip1)第一次调用samples

print(list(zip(samples)))
#[([[['A', 'E'], ['B', 'F']], [['C', 'G'], ['D', 'H']]],),
# ([[['1'], ['2']], [['3'], ['4']]],)]

请注意,在上面输出的两行中,如果元素被展平,您将拥有zip获得最终结果所需的结构。

2) 使用itertools.chainto 展平(这将比使用 更有效sum)。

print([list(chain.from_iterable(*x)) for x in zip(samples)])
#[[['A', 'E'], ['B', 'F'], ['C', 'G'], ['D', 'H']],
# [['1'], ['2'], ['3'], ['4']]]

3)现在zip再次调用:

print(list(zip(*((chain.from_iterable(*x)) for x in zip(samples)))))
#[(['A', 'E'], ['1']),
# (['B', 'F'], ['2']),
# (['C', 'G'], ['3']),
# (['D', 'H'], ['4'])]

4)现在你基本上有了你想要的,除了列表是嵌套的。所以itertools.chain再次使用来展平最终列表。

print(
    [
        list(chain.from_iterable(y)) for y in zip(
            *((chain.from_iterable(*x)) for x in zip(samples))
        )
    ]
)
#[['A', 'E', '1'], ['B', 'F', '2'], ['C', 'G', '3'], ['D', 'H', '4']]

推荐阅读