【问题标题】:Turn Python list from CSV with multi-value fields into a Python nested list, sort nested list values and export to CSV将具有多值字段的 CSV 中的 Python 列表转换为 Python 嵌套列表,对嵌套列表值进行排序并导出为 CSV
【发布时间】:2015-05-07 03:48:28
【问题描述】:

我使用 Python csv 模块将具有多值字段的 csv 转换为 Python list。输出包含具有多个相关值的字段。

['Route', 'Vehicles', 'Vehicle Class', 'Driver_ID', 'Date', 'Start', 'Arrive']
['ABC', 'ZYG098, AB0134, GF0158', 'A1, B2, C3', 'John Doe, Jane Doe, Abraham Lincoln', '20150301', 'A', 'B']
['AC', 'ZGA123', 'C3', 'George Washington', '20150301', 'A', 'C']
['ABC', 'XAZ012, AB0134, YZ089', 'C1, B2, A2 ', 'John Adams, Jane Doe, Thomas Jefferson', '20150302', 'A', 'B']

我想将 Vehicles、Vehicle Class 和 Driver ID 字段转换为嵌套列表,这样如果我对 Vehicle row[1] 中的每个子列表进行排序,以确保车辆始终按字母顺序出现在子列表中,并且车辆类别和驾驶员保持各自正确的顺序。所以标题和第一行子列表的排列方式如下:

['Route', 'Vehicles', 'Vehicle Class', 'Driver_ID', 'Date', 'Start', 'Arrive']
['ABC', 'AB0134, GF0158, ZYG098', 'B2, C3, A1', 'Jane Doe, Abraham Lincoln, John Doe', '20150301', 'A', 'B']
['AC', 'ZGA123', 'C3', 'George Washington', '20150301', 'A', 'C']
['ABC', 'AB0134, YZ089, XAZ012', 'B2, A2, C1', 'Jane Doe, Thomas Jefferson, John Adams', '20150302', 'A', 'B']

因此,在上面的输出中,车辆的每个子组/列表都按字母顺序排序,并且根据需要重新排列车辆类别和驾驶员 ID,以保持它们与各自车辆的原始关系(即驾驶员 ID - John Doe 驾驶Vehicle - ZYG098 是 Vehicle Class - A1,因此这些项目在其子列表中移动以反映 ZYG098 现在是最后一个,而不是第一个)。如果可以做到这一点,您将如何将生成的嵌套列表导出回带有原始标题的 CSV?

抱歉,如果这很简单或荒谬,我刚刚开始学习 Python。如果嵌套列表不是最佳选择,我愿意接受任何其他解决方案(对于字典,我需要加入字段来创建键,因为没有组合 Route_Date 就没有唯一键)。如果有人有可靠的资源来使用 Python 处理各种 CSV 用例,那么推荐会很棒。

提前感谢您的耐心和帮助。

【问题讨论】:

    标签: python list csv nested


    【解决方案1】:

    终于在同一页面上,花了一些工作,但这会做你想要的:

    from itertools import chain
    import csv
    
    
    l = [['Route', 'Vehicles', 'Vehicle Class', 'Driver_ID', 'Date', 'Start', 'Arrive'],
         ['ABC', 'ZYG098, AB0134, GF0158', 'A1, B2, C3', 'John Doe, Jane Doe, Abraham Lincoln', '20150301', 'A', 'B'],
         ['AC', 'ZGA123', 'C3', 'George Washington', '20150301', 'A', 'C'],
         ['ABC', 'XAZ012, AB0134, YZ089', 'C1, B2, A2 ', 'John Adams, Jane Doe, Thomas Jefferson', '20150302', 'A', 'B']]
    it = map(list,zip(*l))
    
    # transpose original list, row-columns, columns-rows
    it =  zip(*l)
    
    # get each column separately, using iter so we can pop first element
    # off to get headers efficiently 
    route, veh, veh_c, d_id, date, start, arrive = iter(iter(next(it))), iter(next(it)), iter(next(it)), iter(next(it)), iter(next(it)), iter(next(it)), iter(next(it))
    
    # get all headers to write later
    headers = next(route), next(veh), next(veh_c), next(d_id), next(date), next(start), next(arrive)
    
    srt_veh = []
    key_inds = []
    
    # sort vehicle elements and keep a record of old indexes
    # so subelements in Vehicle_class and driver_id can be rearranged to match
    for x in veh:
        srt = sorted(x.split(","))
        key_inds.append([x.split(",").index(w) for w in srt])
        srt_veh.append(",".join(srt).strip())
    
    srt_veh_cls = []
    
    # sort vehicle class based on old index of elements in vehicles
    # and rejoin split elements
    for ind, ele in enumerate(veh_c):
        spl = ele.split(",")
        srt_veh_cls.append(",".join([spl[i].strip() for i in key_inds[ind]]))
    
    srt_dr_id = []
    
    # sort driver_ids  based on old index of elements in vehicle
    # and join subelements again after splitting and sorting
    for ind, ele in enumerate(d_id):
        spl = ele.split(",")
        srt_dr_id.append(",".join([spl[i].strip() for i in key_inds[ind]]))
    
     # transpose again for writing
    zipped = zip(*(route, srt_veh, srt_veh_cls,
               srt_dr_id, date, start, arrive))
    

    终于用 csv.writerows 写了:

    with open("out.csv", "w") as f:
        wr = csv.writer(f)
        wr.writerow(headers)
        wr.writerows(zipped)
    

    输出:

    Route,Vehicles,Vehicle Class,Driver_ID,Date,Start,Arrive
    ABC,"AB0134, GF0158,ZYG098","B2,C3,A1","Jane Doe,Abraham Lincoln,John Doe",20150301,A,B
    AC,ZGA123,C3,George Washington,20150301,A,C
    ABC,"AB0134, YZ089,XAZ012","B2,A2,C1","Jane Doe,Thomas Jefferson,John Adams",20150302,A,B
    

    对于 python 2,将 zip 替换为 itertools.izip,将 map 替换为 itertools.imap

    from itertools import izip, imap
    

    您可以压缩更多内容并做一些事情来缩短代码,但我认为这无助于提高可读性。

    【讨论】:

    • 非常感谢,我很抱歉,我没有很好地解释我想要排序的方式。我打算按字母顺序对每个 Vehicle 子列表进行排序,并维护 Vehicle Class 和 Driver_ID 各自的正确顺序。我更新了原始帖子以澄清,希望现在更有意义。
    • 同样的逻辑,我们只需要添加一个额外的循环,我将编辑,您只想对一列进行排序?
    • @Triadelphia,检查编辑,看看我们是否在同一页面上
    • Padraic,并不是真正的列排序,而是列中的每个子列表。我需要按字母顺序排列 Vehicle 列中的每个子列表,还需要重新排列每一行的 Vehicle Class 和 Driver_ID 子列表以保持关系。无需对整列进行排序,而是对每一行中的子列表进行排序。我在原始帖子中包含了所需输出的示例,其中包含已排序的车辆以及基于排序的车辆子列表重新排列的车辆类和 Driver_ID。再次感谢
    • 所以基本上你想要['ABC', 'ZYG098, AB0134, GF0158', 'A1, B2, C3', 'John Doe, Jane Doe, Abraham Lincoln', '20150301', 'A', 'B'] 排序?
    【解决方案2】:

    要转换为您描述的嵌套格式:

    nested = zip(*lst)
    

    而 zip 是它自己的逆:

    orig = zip(*nested)
    

    但也许你真正想要的是:

    import operator
    
    sort = sorted(lst[1:], key=operator.itemgetter(1))
    

    这为您提供了一个按第 1 行排序的新列表。在这种情况下,您没有更改数据的格式,因此您应该能够将其转储为 csv 而无需修改,尽管您需要预先添加来自 lst[0] 的原始标题。

    【讨论】:

    • 非常感谢,我很抱歉,我没有很好地解释我想要排序的方式。我打算按字母顺序对每个 Vehicle 子列表进行排序,并维护 Vehicle Class 和 Driver_ID 各自的正确顺序。我更新了原始帖子以澄清,希望现在更有意义。
    猜你喜欢
    • 1970-01-01
    • 2010-09-21
    • 1970-01-01
    • 1970-01-01
    • 2014-08-04
    • 2017-06-17
    • 1970-01-01
    • 2011-09-30
    • 1970-01-01
    相关资源
    最近更新 更多