Python 3.x 将不同长度的嵌套列表的Python dict导出为csv。如果嵌套列表具有>;1项,在移动到下一个关键点之前展开到列

Python 3.x 将不同长度的嵌套列表的Python dict导出为csv。如果嵌套列表具有>;1项,在移动到下一个关键点之前展开到列,python-3.x,csv,dictionary,nested-lists,Python 3.x,Csv,Dictionary,Nested Lists,我有下面的列表词典 d = {1: ['1','B1',['C1','C2','C3']], 2: ['2','B2','C15','D12'], 3: ['3','B3'], 4: ['4', 'B4', 'C4', ['D1', 'D2']]} 使用以下命令将其写入csv with open('test.csv', "w", newline = '') as f: writer = csv.writer(f) writer.writerow(headers) writer.writerow

我有下面的列表词典

d = {1: ['1','B1',['C1','C2','C3']], 2: ['2','B2','C15','D12'], 3: ['3','B3'], 4: ['4', 'B4', 'C4', ['D1', 'D2']]}
使用以下命令将其写入csv

with open('test.csv', "w", newline = '') as f:
writer = csv.writer(f)
writer.writerow(headers)
writer.writerows(d.values())
给我一个csv,看起来像

A     B            C                D
1    B1     ['C1','C2',C3']
2    B2           C15             D12
3    B3
4    B4            C4          ['D1','D2']
如果值中有一个多项目列表(嵌套列表?),我希望该列表按如下方式向下展开

A     B     C      D
1    B1    C1
1          C2 
1          C3
2    B2    C15    D12
3    B3
4    B4    C4      D1
4                  D2
我对python还相当陌生,在经过几天的论坛筛选和把头撞到墙上之后,似乎无法找到一种方法来做我需要的事情。我想我可能需要分解嵌套列表,但我需要将它们与各自的“A”值绑定。列A和B将始终有1个条目,列C和D可以有1到X个条目


非常感谢您提供的任何帮助

似乎创建一个包含适当位置空白的列表比您正在做的事情更容易。下面是一些可能的方法:

import csv
from itertools import zip_longest

def condense(dct):
    # get the maximum number of columns of any list
    num_cols = len(max(dct.values(), key=len)) - 1
    # Ignore the key, it's not really relevant.
    for _, v in dct.items():
        # first, memorize the index of this list, 
        # since we need to repeat it no matter what
        idx = v[0]
        # next, use zip_longest to make a correspondence.
        # We will deliberately make a 2d list, 
        # and we will later withdraw elements from it one by one.
        matrix = [([]     if elem is None else
                   [elem] if not isinstance(elem, list) else 
                   elem[:]  # soft copy to avoid altering original dict
                  ) for elem, _ in zip_longest(v[1:], range(num_cols), fillvalue=None)
                 ]
        # Now, we output the top row of the matrix as long as it has contents
        while any(matrix):
            # If a column in the matrix is empty, we put an empty string.
            # Otherwise, we remove the row as we pass through it,
            # progressively emptying the matrix top-to-bottom
            # as we output a row, we also remove that row from the matrix.
            # *-notation is more convenient than concatenating these two lists.
            yield [idx, *((col.pop(0) if col else '') for col in matrix)] 
            # e.g. for key 0 and a matrix that looks like this:
            #    [['a1', 'a2'],
            #     ['b1'],
            #     ['c1', 'c2', 'c3']]
            # this would yield the following three lists before moving on:
            #    ['0', 'a1', 'b1', 'c1']
            #    ['0', 'a2', '',   'c2']
            #    ['0', '',   '',   'c3']
            # where '' should parse into an empty column in the resulting CSV.
这里需要注意的最大的一点是,我使用
isinstance(elem,list)
作为一种速记,来检查这个东西是否是一个列表(你需要能够以这样或那样的方式使列表变平或变圆,就像我们在这里做的那样)。如果您有更复杂或更多样的数据结构,则需要临时执行此检查-可能需要编写一个帮助函数
isiterable()
,该函数尝试迭代并根据这样做是否产生错误返回布尔值

完成后,我们可以在
d
上调用
consolate()
,并让
csv
模块处理输出

headers = ['A', 'B', 'C', 'D']
d = {1: ['1','B1',['C1','C2','C3']], 2: ['2','B2','C15','D12'], 3: ['3','B3'], 4: ['4', 'B4', 'C4', ['D1', 'D2']]}

# condense(d) produces
#   [['1', 'B1', 'C1',  ''   ], 
#    ['1', '',   'C2',  ''   ], 
#    ['1', '',   'C3',  ''   ], 
#    ['2', 'B2', 'C15', 'D12'], 
#    ['3', 'B3', '',     ''  ], 
#    ['4', 'B4', 'C4',  'D1' ], 
#    ['4', '',   '',    'D2' ]]

with open('test.csv', "w", newline = '') as f:
    writer = csv.writer(f)
    writer.writerow(headers)
    writer.writerows(condense(d))
将生成以下文件:

A,B,C,D
1,B1,C1,
1,,C2,
1,,C3,
2,B2,C15,D12
3,B3,,
4,B4,C4,D1
4,,,D2

这相当于您的预期输出。希望该解决方案具有足够的可扩展性,您可以将其应用于非MVCE问题。

似乎创建一个包含适当位置空白的列表比您正在做的更容易。下面是一些可能的方法:

import csv
from itertools import zip_longest

def condense(dct):
    # get the maximum number of columns of any list
    num_cols = len(max(dct.values(), key=len)) - 1
    # Ignore the key, it's not really relevant.
    for _, v in dct.items():
        # first, memorize the index of this list, 
        # since we need to repeat it no matter what
        idx = v[0]
        # next, use zip_longest to make a correspondence.
        # We will deliberately make a 2d list, 
        # and we will later withdraw elements from it one by one.
        matrix = [([]     if elem is None else
                   [elem] if not isinstance(elem, list) else 
                   elem[:]  # soft copy to avoid altering original dict
                  ) for elem, _ in zip_longest(v[1:], range(num_cols), fillvalue=None)
                 ]
        # Now, we output the top row of the matrix as long as it has contents
        while any(matrix):
            # If a column in the matrix is empty, we put an empty string.
            # Otherwise, we remove the row as we pass through it,
            # progressively emptying the matrix top-to-bottom
            # as we output a row, we also remove that row from the matrix.
            # *-notation is more convenient than concatenating these two lists.
            yield [idx, *((col.pop(0) if col else '') for col in matrix)] 
            # e.g. for key 0 and a matrix that looks like this:
            #    [['a1', 'a2'],
            #     ['b1'],
            #     ['c1', 'c2', 'c3']]
            # this would yield the following three lists before moving on:
            #    ['0', 'a1', 'b1', 'c1']
            #    ['0', 'a2', '',   'c2']
            #    ['0', '',   '',   'c3']
            # where '' should parse into an empty column in the resulting CSV.
这里需要注意的最大的一点是,我使用
isinstance(elem,list)
作为一种速记,来检查这个东西是否是一个列表(你需要能够以这样或那样的方式使列表变平或变圆,就像我们在这里做的那样)。如果您有更复杂或更多样的数据结构,则需要临时执行此检查-可能需要编写一个帮助函数
isiterable()
,该函数尝试迭代并根据这样做是否产生错误返回布尔值

完成后,我们可以在
d
上调用
consolate()
,并让
csv
模块处理输出

headers = ['A', 'B', 'C', 'D']
d = {1: ['1','B1',['C1','C2','C3']], 2: ['2','B2','C15','D12'], 3: ['3','B3'], 4: ['4', 'B4', 'C4', ['D1', 'D2']]}

# condense(d) produces
#   [['1', 'B1', 'C1',  ''   ], 
#    ['1', '',   'C2',  ''   ], 
#    ['1', '',   'C3',  ''   ], 
#    ['2', 'B2', 'C15', 'D12'], 
#    ['3', 'B3', '',     ''  ], 
#    ['4', 'B4', 'C4',  'D1' ], 
#    ['4', '',   '',    'D2' ]]

with open('test.csv', "w", newline = '') as f:
    writer = csv.writer(f)
    writer.writerow(headers)
    writer.writerows(condense(d))
将生成以下文件:

A,B,C,D
1,B1,C1,
1,,C2,
1,,C3,
2,B2,C15,D12
3,B3,,
4,B4,C4,D1
4,,,D2

这相当于您的预期输出。希望该解决方案具有足够的可扩展性,您可以将其应用于非MVCE问题。

GCG-这正是我所需要的!非常感谢您花时间提供完整的答案和解释。我会花些时间分析你发来的东西,但你让我“不卡住”。我试图标记为有用,但下面我是15个代表…GCG-这正是我需要的!非常感谢您花时间提供完整的答案和解释。我会花些时间分析你发来的东西,但你让我“不卡住”。我试着标记为有用,但下面我是15个代表。。。