【问题标题】:Sorting CSV in Python在 Python 中对 CSV 进行排序
【发布时间】:2011-01-06 12:54:51
【问题描述】:

我假设使用 Python 对多个文本/数字字段上的 CSV 文件进行排序将是一个已经解决的问题。但是我在任何地方都找不到任何示例代码,除了专注于排序日期字段的特定代码。

如何按顺序对多个字段上的相对较大的 CSV 文件(数万行)进行排序?

Python 代码示例将不胜感激。

【问题讨论】:

    标签: python sorting csv


    【解决方案1】:

    这是 Alex 的答案,经过重新设计以支持列数据类型:

    import csv
    import operator
    
    def sort_csv(csv_filename, types, sort_key_columns):
        """sort (and rewrite) a csv file.
        types:  data types (conversion functions) for each column in the file
        sort_key_columns: column numbers of columns to sort by"""
        data = []
        with open(csv_filename, 'rb') as f:
            for row in csv.reader(f):
                data.append(convert(types, row))
        data.sort(key=operator.itemgetter(*sort_key_columns))
        with open(csv_filename, 'wb') as f:
            csv.writer(f).writerows(data)
    

    编辑:

    我做了一个傻事。几天前,我在 IDLE 中玩各种东西,并写了一个 convert 函数。我忘了我已经写过了,而且我很久没有关闭 IDLE - 所以当我写上面的时候,我认为convert 是一个内置函数。可惜没有。

    这是我的实现,虽然 John Machin 的更好:

    def convert(types, values):
        return [t(v) for t, v in zip(types, values)]
    

    用法:

    import datetime
    def date(s):
        return datetime.strptime(s, '%m/%d/%y')
    
    >>> convert((int, date, str), ('1', '2/15/09', 'z'))
    [1, datetime.datetime(2009, 2, 15, 0, 0), 'z']
    

    【讨论】:

    • 什么是 convert() 函数?另外,是第二个和第三个参数列表吗?
    • sort_csv('myfile.csv', [?, ?, ?, ?], ['Name', 'BirthDate', 'Age', 'Price']
    • @Pranab:第二个和第三个参数都可以是任何可迭代的
    • convert 函数是啊,我忘记包含了。见编辑。如果您想按最后两列对四列 CSV 文件进行排序,您可以使用类似 sort_csv('myfile.csv', (str, int, float, int), (2, 3)) 的方式调用此函数。
    【解决方案2】:

    这是罗伯特修复亚历克斯答案中缺少的convert()

    >>> def convert(convert_funcs, seq):
    ...    return [
    ...        item if func is None else func(item)
    ...        for func, item in zip(convert_funcs, seq)
    ...        ]
    ...
    >>> convert(
    ...     (None, float, lambda x: x.strip().lower()),
    ...     [" text ", "123.45", " TEXT "]
    ...     )
    [' text ', 123.45, 'text']
    >>>
    

    我更改了第一个参数的名称,以强调 per-columns 函数可以满足您的需求,而不仅仅是类型强制。 None 用于表示没有转化。

    【讨论】:

      【解决方案3】:

      你提出了 3 个问题:

      • 文件大小
      • csv 数据
      • 对多个字段进行排序

      这是第三部分的解决方案。您可以以更复杂的方式处理 csv 数据。

      >>> data = 'a,b,c\nb,b,a\nb,c,a\n'
      >>> lines = [e.split(',') for e in data.strip().split('\n')]
      >>> lines
      [['a', 'b', 'c'], ['b', 'b', 'a'], ['b', 'c', 'a']]
      >>> def f(e):
      ...     field_order = [2,1]
      ...     return [e[i] for i in field_order]
      ... 
      >>> sorted(lines, key=f)
      [['b', 'b', 'a'], ['b', 'c', 'a'], ['a', 'b', 'c']]
      

      编辑为使用列表推导,生成器无法像我预期的那样工作。

      【讨论】:

        【解决方案4】:

        Python 的排序只在内存中工作;然而,在现代机器上,数以万计的行应该很容易放入内存中。所以:

        import csv
        
        def sortcsvbymanyfields(csvfilename, themanyfieldscolumnnumbers):
          with open(csvfilename, 'rb') as f:
            readit = csv.reader(f)
            thedata = list(readit)
          thedata.sort(key=operator.itemgetter(*themanyfieldscolumnnumbers))
          with open(csvfilename, 'wb') as f:
            writeit = csv.writer(f)
            writeit.writerows(thedata)
        

        【讨论】:

        • 这就是为什么我需要花一个周末(或一周),查看标准库参考。 itemgetter 看起来很可爱。
        • 这没有解决 OP 的“多个文本/数字字段”要求;它将所有字段视为文本。
        • @John,如果在排序完成之前需要对某些字段进行不同的处理(例如,进行诸如多个不同类型强制的转换),这并不难安排,但是没有足够的规范Q 中详细介绍了函数参数如何指定这样一个潜在的复杂问题(毫无疑问,值得单独的 Q,因为它可能很重要,而不是排序!)——如果你想要那个信息,为什么不自己打开一个 Q ?
        • 顺便说一句,通常 csv 的第一行是标题 - 小心在排序中省略它
        猜你喜欢
        • 2015-06-14
        • 2017-06-23
        • 1970-01-01
        • 1970-01-01
        • 2010-12-18
        • 2012-04-12
        • 2015-06-18
        • 2021-06-02
        • 2016-07-01
        相关资源
        最近更新 更多