用Python替换CSV文件中的特定行并追加其余行
我有一堆文件名,需要把它们合并到一个新文件里。第一列是日期。如果一个文件的日期和另一个文件的日期重叠,我希望后面的文件能替换掉之前的内容。比如,第一个文件的内容是:
1/5/2010 'hello'
1/6/2010 'goodbye'
1/7/2010 'yes'
第二个文件是:
1/7/2010 'No'
1/8/2010 "spam'
1/9/2010 'today'
我希望我的新文件看起来像这样:
1/5/2010 'hello'
1/6/2010 'goodbye'
1/7/2010 'No'
1/8/2010 'spam'
1/9/2010 'today'
现在我在尝试一些方法,但结果不太对。(reader 2和reader指的是第二个文件和第一个文件,新文件newfile2.csv已经包含了第一个文件的内容)
for row in reader2:
for row2 in reader:
if row == row2:
target = open('newfile2.csv', 'wb')
writer = csv.writer(target)
writer.writerow(row)
target.close()
else:
target = open('newfile2.csv', 'ab')
writer = csv.writer(target)
writer.writerow(row)
target.close()
如果有任何建议,我会非常感激。谢谢!
好吧,我想在看了一些评论后再澄清一下。顺序很重要。在这段代码的最后,我希望每一天的数据都按顺序排列。好消息是,文件里的数据已经是有序的,只是有一些重复。
重复的情况有很多。例如,我处理的第一个文件的数据到3月9日,但我希望它能在2月底结束。我想要第二个文件里的所有3月数据。
另外,文件里有1500多行,因为真实文件中,每一天的每一个小时也都包含在行里。
我希望这能澄清我需要做的事情。
我觉得像我上面发的代码那样,只检查每行的第一列(因为只有日期会重复)可能会有效?现在我检查的是整行,虽然日期重复,但整行内容是独一无二的。
哦,对了,还有最后一件事。我希望所有的重复都能被消除。
3 个回答
如果文件不大(比如只有几千行),那么这个方法可以很好地处理任意数量的输入文件,保持行的顺序,并且只去掉你指定的重复内容。
input_files = 'a.csv, b.csv, c.csv, d.csv'
last = '.'
# open the outfile and make the csv writer here
for input_file in input_files:
# open the infile and make the csv reader here
lines = reader.readlines()
# save the last line for later
last_new = reader.pop()
if last.split()[0] != lines[0].split()[0]:
writer.writeln(last)
writer.writelines(lines)
last = last_new
reader.close()
writer.writeln(last)
writer.close()
如果你想去掉所有的重复项,可以参考其他答案中的dict
方法,但不要用普通的dict
({}
),而是要用collections.OrderedDict()
,这样行的顺序才能保持不变。
对于Python 2.4到2.6版本,OrderedDict
的替代方案可以在这个链接找到:http://pypi.python.org/pypi/ordereddict。
到目前为止,大家给出的答案都是把数据读到内存里,这对于小文件来说没问题。但因为你说你的输入文件已经排好序了,所以可以逐行处理这些文件,这样就能处理任意行数的文件。
假设你有一系列的csv 读取器
(按照优先顺序排列——如果多个文件中有相同的关键字,那么会选择第一个读取器中的那一行),还有一个用于输出的csv 写入器
,以及一个key
函数来提取每一行的排序关键字,你可以始终输出包含最小排序关键字值的那一行,并推进所有具有相同关键字值的读取器:
def combine(readers, writer, key):
rows = [reader.next() for reader in readers]
while rows:
# select the first input row with the minimum sort key value
row = min(rows, key=key)
writer.writerow(row)
# advance all readers with the minimum sort key value
min_key = key(row)
for i in xrange(len(readers)):
if key(rows[i]) == min_key:
try:
rows[i] = readers[i].next()
except StopIteration:
# reader exhausted, remove it
del rows[i]
del readers[i]
要从示例文件中获取可排序的关键字,你需要解析日期,因为它的格式有点奇怪。如果文件中使用ISO %Y-%m-%d
格式的日期,那就简单多了,因为这种格式的日期自然可以排序。
import datetime
def key(row):
return datetime.datetime.strptime(row[0], '%m/%d/%Y')
把这些都结合起来,你就可以运行 python combine.py input1.csv input2.csv > output.csv
。输入文件的顺序是反过来的,这样后面指定的文件会覆盖前面指定的文件。
import csv, sys
delimiter = ' ' # used in the example input files
readers = [csv.reader(open(filename), delimiter=delimiter)
for filename in reversed(sys.argv[1:])]
writer = csv.writer(sys.stdout, delimiter=delimiter);
combine(readers, writer, key)
试试这个:
dictio = {}
for row in reader:
[date, text] = row.split()
dictio[date] = text
for row in reader2:
[date, text] = row.split()
dictio[date] = text
target = open('newfile2.csv', 'wb')
writer = csv.writer(target)
for date, text in dictio.iteritems():
writer.writerow("%s %s" %(date, text))
target.close()
编辑:在评论之后,如果你想保持项目的顺序,可以把
dictio = {}
换成
dictio = collections.OrderedDict()
这个适用于 Python 版本大于 2.6