社区所有版块导航
Python
python开源   Django   Python   DjangoApp   pycharm  
DATA
docker   Elasticsearch  
aigc
aigc   chatgpt  
WEB开发
linux   MongoDB   Redis   DATABASE   NGINX   其他Web框架   web工具   zookeeper   tornado   NoSql   Bootstrap   js   peewee   Git   bottle   IE   MQ   Jquery  
机器学习
机器学习算法  
Python88.com
反馈   公告   社区推广  
产品
短视频  
印度
印度  
Py学习  »  Python

Python的zip可以用来重构更深层次的嵌套列表吗?

Petteri Nevavuori • 5 年前 • 1796 次点击  

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

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
]

我的问题是 是否存在一种利用Python的方法 zip 函数和一些列表理解来实现这一点?

我已经寻找了一些解决办法,但是例如 this this 处理使用 拉链 处理不同的列表,而不是内部列表。

实现这一点的一种方法很可能是对样本进行简单的迭代,如下所示:

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
]

我仍然好奇是否有一种方法可以利用。 拉链 结束 for 循环样本及其嵌套列表。

请注意 data metadata 可以在不同的样本长度上变化。

Python社区是高质量的Python/Django开发社区
本文地址:http://www.python88.com/topic/52049
 
1796 次点击  
文章 [ 4 ]  |  最新文章 5 年前
Georgy
Reply   •   1 楼
Georgy    6 年前

这不是最舒适的数据结构。我建议重构代码并选择3倍嵌套列表之外的其他内容来保存数据,但如果当前不可能,我建议使用以下方法:

import itertools


def flatten(iterable):
    yield from itertools.chain.from_iterable(iterable)


result = []
for elements in zip(*map(flatten, samples)):
    result.append(list(flatten(elements)))

举例来说,它给出了:

[['A', 'E', '1'], 
 ['B', 'F', '2'], 
 ['C', 'G', '3'], 
 ['D', 'H', '4']]

测试2个以上的样品:

samples = [[[['A', 'E'], ['B', 'F']],
            [['C', 'G'], ['D', 'H']]],
           [[['1'], ['2']], 
            [['3'], ['4']]], 
           [[['5'], ['6']],
            [['7'], ['8']]]]

给予:

[['A', 'E', '1', '5'],
 ['B', 'F', '2', '6'],
 ['C', 'G', '3', '7'],
 ['D', 'H', '4', '8']]

说明:

这个 flatten generator function 只需展平嵌套iterable的1个级别。它基于 itertools.chain.from_iterable 功能。在 map(flatten, samples) 我们将此函数应用于 samples :

>>> map(flatten, samples)
<map at 0x3c6685fef0>  # <-- map object returned, to see result wrap it in `list`:

>>> list(map(flatten, samples))
[<generator object flatten at 0x0000003C67A2F9A8>,  # <-- will flatten the 1st sample
 <generator object flatten at 0x0000003C67A2FA98>,  # <-- ... the 2nd
 <generator object flatten at 0x0000003C67A2FB10>]  # <-- ... the 3rd and so on if there are more

# We can see what each generator will give by applying `list` on each one of them
>>> list(map(list, map(flatten, samples)))
[[['A', 'E'], ['B', 'F'], ['C', 'G'], ['D', 'H']],
 [['1'], ['2'], ['3'], ['4']],
 [['5'], ['6'], ['7'], ['8']]]

接下来,我们可以使用 zip 在平坦的样本上迭代。请注意,我们不能将其应用于 map 直接对象:

>>> list(zip(map(flatten, samples)))
[(<generator object flatten at 0x0000003C66944138>,),
 (<generator object flatten at 0x0000003C669441B0>,),
 (<generator object flatten at 0x0000003C66944228>,)]

我们应该 unpack 首先:

>>> list(zip(*map(flatten, samples)))
[(['A', 'E'], ['1'], ['5']),
 (['B', 'F'], ['2'], ['6']),
 (['C', 'G'], ['3'], ['7']),
 (['D', 'H'], ['4'], ['8'])]

# or in a for loop:
>>> for elements in zip(*map(flatten, samples)):
...     print(elements)
(['A', 'E'], ['1'], ['5'])
(['B', 'F'], ['2'], ['6'])
(['C', 'G'], ['3'], ['7'])
(['D', 'H'], ['4'], ['8'])

最后,我们只需要加入每个 elements 把元组放在一起。我们可以用同样的 扁平化 功能:

>>> for elements in zip(*map(flatten, samples)):
...     print(list(flatten(elements)))
['A', 'E', '1', '5']
['B', 'F', '2', '6']
['C', 'G', '3', '7']
['D', 'H', '4', '8']

您只需将其全部放回一个列表中,如第一个代码示例所示。

Tomerikoo
Reply   •   2 楼
Tomerikoo    6 年前

你可以:

res = [[y for l in x for y in l] for x in zip(*([x for var in sample for x in var] for sample in samples))]

print([list(i) for i in res])

举例说明:

[['A', 'E', '1'], ['B', 'F', '2'], ['C', 'G', '3'], ['D', 'H', '4']]

这基本上是将每个“样本”展平到一个列表中,并将其打包到一个大列表中,然后将其解压缩到 zip 然后将每个压缩元素打包到一个列表中。

L3viathan
Reply   •   3 楼
L3viathan    6 年前

这是另一个解决方案。很难看,但它确实有用 zip ,甚至两次!

>>> sum(map(lambda y: list(map(lambda x: sum(x, []), zip(*y))), zip(*samples)), [])
[['A', '1'], ['B', '2'], ['C', '3'], ['D', '4']]

看看它是如何工作的很有意思,但请不要实际使用它;它既难阅读,又算法不好。

pault
Reply   •   4 楼
pault    6 年前

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

循序渐进的解释

1) 第一次通话 zip samples :

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

注意,在上面输出的两行中,如果元素被展平,您将拥有 拉链 为了得到你的最终结果。

2) 使用 itertools.chain to flatten (这将是很多 more efficient than using 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) 现在打电话 拉链 再一次:

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