Сортировка CSV в Python
Я предположил, что сортировка CSV-файла по нескольким текстовым / числовым полям с использованием Python будет проблемой, которая уже решена. Но я не могу найти никакого примера кода нигде, кроме конкретного кода, ориентированного на сортировку полей даты.
Как можно сортировать относительно большой CSV-файл (десятки тысяч строк) по нескольким полям по порядку?
образцы кода Python будут оценены.
4 ответов
вот ответ Алекса, переработанный для поддержки типов данных столбцов:
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)
Edit:
Я сделал глупость. Я играл с различными вещами в IDLE и написал пару дней назад. Я забыла, что написала его,и уже давно не закрывала "простоя", поэтому, когда я написала все это, я подумала ...--3--> была встроенной функцией. К сожалению, нет.
вот моя реализация, хотя Джон Мэчин лучше:
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']
сортировка 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)
здесь 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']
>>>
Я изменил имя первого arg, чтобы подчеркнуть, что функция per-columns может делать то, что вам нужно, а не просто принуждение типа. None
используется для указания на преобразование.
вы поднимаете 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']]
отредактировано для использования понимания списка, генератор работает не так, как я ожидал.