如何将字典和单个项目的列表展平为应复制单个项目的列表

How to flatten a list of dicts and single items into a list where single items should be duplicated

我有这个数组:

import numpy as np

array_start = [{'Very Ripe': 5}, {'Ripe': 2}, np.nan]

我想生成一个包含各个项目的数组并复制 np.nan 值,以便我最终得到这个数组:

>>> array_end
['Very Ripe', 5, 'Ripe', 2, nan, nan]

到目前为止我已经尝试了以下方法:

>>> array_end = [item.items() if isinstance(item,dict) else np.repeat(np.nan,2) for item in array_start]
>>> array_end
[dict_items([('Very Ripe', 5)]), dict_items([('Ripe', 2)]), array([nan, nan])]

这让我有所收获,但似乎更难解压缩 dict_itemsarray_end 中的后一个数组(np.nans)以生成目标 array_end:

['Very Ripe', 5, 'Ripe', 2, nan, nan]

是否必须在单列表理解中?不要让简洁成为功能代码的敌人。

这是一种使用两个列表理解的方法:

array_end = [list(*item.items()) if isinstance(item,dict) else np.repeat(np.nan,2) for item in array_start]
print(array_end)
# Output: [['Very Ripe', 5], ['Ripe', 2], array([nan, nan])]

我们在第一个列表理解中将 dict_items() 对象解包到列表中。然后,我们有一个列表列表(或 numpy 数组),我们可以 运行 另一个理解来展平它。

array_final = [y for x in array_end for y in x]
print(array_final)
# Output: ['Very Ripe', 5, 'Ripe', 2, nan, nan]

您可以遍历 array_list 中的每个项目,检查它是否是字典,如果不是,则复制该项目,如果是,则提取所有字典项目。您有多种选择可以使用

一个简单的循环 list.extend:

import numpy as np

array_start = [{'Very Ripe': 5}, {'Ripe': 2}, np.nan]

result = []
for element in array_start:
    if isinstance(element, dict):
        for item in element.items():
            result.extend(item)
    else:
        result.extend((element, element))
print(result)
# ['Very Ripe', 5, 'Ripe', 2, nan, nan]

生成器函数:

def to_flat_list(array):
    for element in array:
        if isinstance(element, dict):
            for item in element.items():
                yield from item
        else:
            yield element
            yield element

            
result = list(to_flat_list(array_start))
print(result)
# ['Very Ripe', 5, 'Ripe', 2, nan, nan]

列表理解中的嵌套循环:

result = [item 
          for element in array_start
          for pair in (element.items() if isinstance(element, dict) 
                       else [(element, element)])
          for item in pair]
print(result)
# ['Very Ripe', 5, 'Ripe', 2, nan, nan]

itertools.chain.from_iterable:

from itertools import chain

flatten = chain.from_iterable
result = list(flatten((flatten(item.items()) 
                       if isinstance(item, dict) 
                       else (item, item) 
                       for item in array_start)))
print(result)
# ['Very Ripe', 5, 'Ripe', 2, nan, nan]

可能还有其他一些方法。但这些应该足够了。