用Python替换CSV文件中的特定行并追加其余行

0 投票
3 回答
1466 浏览
提问于 2025-04-16 22:14

我有一堆文件名,需要把它们合并到一个新文件里。第一列是日期。如果一个文件的日期和另一个文件的日期重叠,我希望后面的文件能替换掉之前的内容。比如,第一个文件的内容是:

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 个回答

0

如果文件不大(比如只有几千行),那么这个方法可以很好地处理任意数量的输入文件,保持行的顺序,并且只去掉你指定的重复内容。

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

0

到目前为止,大家给出的答案都是把数据读到内存里,这对于小文件来说没问题。但因为你说你的输入文件已经排好序了,所以可以逐行处理这些文件,这样就能处理任意行数的文件。

假设你有一系列的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)
1

试试这个:

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

撰写回答