按列对CSV进行排序

43

我想按日期对CSV表格进行排序。开始时这似乎是一个简单的任务:

import sys
import csv

reader = csv.reader(open("files.csv"), delimiter=";")

for id, path, title, date, author, platform, type, port in reader:
    print date

我使用了Python的CSV模块来读取一个具有以下结构的文件:

id;file;description;date;author;platform;type;port
  • 日期采用ISO-8601格式,因此我可以很容易地对其进行排序,例如:2003-04-22。
  • 我想按照日期排序,最新的条目排在前面。
  • 我该如何将这个读取器转换成可排序的数据结构?我认为我可以创建一个日期列表:datelist += date,然后对其进行分割和排序。但是我必须重新识别CSV表中完整的条目。这不仅仅是对一些东西进行排序。
  • 似乎csv没有内置的排序函数。

最理想的解决方案是拥有一个类似数据库的CSV客户端处理文件。我没有找到这样的东西。

希望能有人在这里提供一些好的排序方法 :)


2
如果您只是想要一个用于排序CSV文件的工具,请查看我的FOSS项目csvfix,网址为http://code.google.com/p/csvfix/。 - anon
6个回答

82

由于列中的'date'索引为3,

import operator
sortedlist = sorted(reader, key=operator.itemgetter(3), reverse=True)

或者使用lambda

sortedlist = sorted(reader, key=lambda row: row[3], reverse=True)

这会重写文件吗,还是只是将排序后的列表保存在变量中? - Jeff
4
@Jeff:它不会影响原始文件。如果您想将结果写出来,则必须作为单独的操作执行。 - Ignacio Vazquez-Abrams
@IgnacioVazquez-Abrams 这两种方法有什么区别,它们在做什么?应该选择哪一个? - abaumg
@abaumg:从功能上来说,它们是相同的。它们之间可能存在一些小的速度差异,但除非文件中有数百万条记录,否则这可能并不重要。 - Ignacio Vazquez-Abrams
1
这是一种非常好的通用方法,如果您将数据加载到包含列列表的行列表中,则该方法也适用。太棒了 - 谢谢! - gies0r
谁在寻找csv数据框的排序: csvData.sort_values(["date"], axis=0, ascending=[False], inplace=True) - Marek Bernád

21

多列排序(先按column_1排序,然后再按column_2排序)

with open('unsorted.csv',newline='') as csvfile:
    spamreader = csv.DictReader(csvfile, delimiter=";")
    sortedlist = sorted(spamreader, key=lambda row:(row['column_1'],row['column_2']), reverse=False)


with open('sorted.csv', 'w') as f:
    fieldnames = ['column_1', 'column_2', column_3]
    writer = csv.DictWriter(f, fieldnames=fieldnames)
    writer.writeheader()
    for row in sortedlist:
        writer.writerow(row)

3
这里需要考虑CSV文件的标题行! - Foreever

12

该阅读器的行为类似于生成器。在一个带有一些虚假数据的文件上:

>>> import sys, csv
>>> data = csv.reader(open('data.csv'),delimiter=';')
>>> data
<_csv.reader object at 0x1004a11a0>
>>> data.next()
['a', ' b', ' c']
>>> data.next()
['x', ' y', ' z']
>>> data.next()
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
StopIteration

根据Ignacio的建议,使用operator.itemgetter:

>>> data = csv.reader(open('data.csv'),delimiter=';')
>>> import operator
>>> sortedlist = sorted(data, key=operator.itemgetter(2), reverse=True)
>>> sortedlist
[['x', ' y', ' z'], ['a', ' b', ' c']]

2

如果要按列排序csv文件,我会使用以下代码:

import pandas
csvData = pandas.read_csv('myfile.csv')
csvData.sort_values(["date"], axis=0, ascending=[False], inplace=True)
print(csvData)

0

你可以使用Pandas来完成,而且非常简单。

import pandas as pd
df = pd.read_csv("File.csv")
sorted_df = df.sort_values(by=["price","title",...], ascending=False)
sorted_df.to_csv('homes_sorted.csv', index=False)

sort_values方法会返回一个新的数据框,所以请确保将其赋值给一个新变量。


0

结合Ignacio Vazquez-AbramTiina所给出的答案:

fieldnames = [ 'id', 'path', 'title', 'date', 'author', 'platform', 'type', 'port' ]

# this means: order by 'id', 'path', ..., 'port'
items = ('id', 'path', 'title', 'date', 'author', 'platform', 'type', 'port')
  
with open('unsorted.csv',newline='') as csvfile:
    spamreader = csv.DictReader(csvfile, delimiter=";")
    import operator
    sortedlist = sorted(reader, key=operator.itemgetter(*items), reverse=True)

with open('sorted.csv', 'w') as f:
    writer = csv.DictWriter(f, fieldnames=fieldnames)
    writer.writeheader()
    for row in sortedlist:
        writer.writerow(row)

通过这个,你可以

1-按多列排序行。

2-更改要按行排序的列数,而无需使用lambda表达式。

sortedlist = sorted(spamreader, key=lambda row:(row['column_1'],row['column_2']), reverse=False)

特别是,未来如果您想按不同的列顺序对其他CSV文件进行排序,而无需在lambda表达式中添加和删除列模式。
例如:
items = ('path', 'title')

items = ('id', 'path', 'title', 'date')

items = ('author', 'date', 'title')

替代

sortedlist = sorted(spamreader, key=lambda row:(row['column_2'],row['column_3']), reverse=False)

sortedlist = sorted(spamreader, key=lambda row:(row['column_1'],row['column_2'],,row['column_3'],row['column_4']), reverse=False)

sortedlist = sorted(spamreader, key=lambda row:(row['column_5'],row['column_4'],row['column_3']), reverse=False)

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接