Python 如何删除重复行

Python 如何删除重复行,python,text-files,Python,Text Files,我试图创建一个简单的程序,从文件中删除重复的行。然而,我被卡住了。我的目标是最终删除除1个重复行以外的所有行,与建议的重复行不同。所以,我仍然有这些数据。我也想这样做,它接受相同的文件名,并输出相同的文件名。当我试图使两个文件名相同时,它只输出一个空文件 input_file = "input.txt" output_file = "input.txt" seen_lines = set() outfile = open(output_file, "w") for line in open(

我试图创建一个简单的程序,从文件中删除重复的行。然而,我被卡住了。我的目标是最终删除除1个重复行以外的所有行,与建议的重复行不同。所以,我仍然有这些数据。我也想这样做,它接受相同的文件名,并输出相同的文件名。当我试图使两个文件名相同时,它只输出一个空文件

input_file = "input.txt"
output_file = "input.txt"

seen_lines = set()
outfile = open(output_file, "w")

for line in open(input_file, "r"):
    if line not in seen_lines:
        outfile.write(line)
        seen_lines.add(line)

outfile.close()

input.txt

I really love christmas
Keep the change ya filthy animal
Pizza is my fav food
Keep the change ya filthy animal
Did someone say peanut butter?
Did someone say peanut butter?
Keep the change ya filthy animal

预期产量

I really love christmas
Keep the change ya filthy animal
Pizza is my fav food
Did someone say peanut butter?

问题是,您试图写入的文件与读取的文件相同。您至少有两种选择:

选择1 使用不同的文件名(例如input.txt和output.txt)。在某种程度上,这是最简单的

选择2 从输入文件中读取所有数据,关闭该文件,然后打开该文件进行写入

with open('input.txt', 'r') as f:
    lines = f.readlines()

seen_lines = set()
with open('input.txt', 'w') as f:
    for line in lines:
        if line not in seen_lines:
            seen_lines.add(line)
            f.write(line)
选择3 使用
r+
模式打开文件进行读写。在这种情况下,在写入之前读取要处理的数据时需要小心。如果在单个循环中执行所有操作,循环迭代器可能会失去跟踪

import os
seen_lines = []

with open('input.txt','r') as infile:
    lines=infile.readlines()
    for line in lines:
        line_stripped=line.strip()
        if line_stripped not in seen_lines:
            seen_lines.append(line_stripped)

with open('input.txt','w') as outfile:
    for line in seen_lines:
        outfile.write(line)
        if line != seen_lines[-1]:
            outfile.write(os.linesep)
输出:

I really love christmas
Keep the change ya filthy animal
Pizza is my fav food
Did someone say peanut butter?

outfile=open(output_file,“w”)
会截断文件,不管您做什么。接下来的读取将找到一个空文件。我建议安全地执行此操作,使用临时文件:

  • 打开临时文件进行写入
  • 将输入处理为新输出
  • 关闭两个文件
  • 将临时文件移到输入文件名
  • 这比两次打开文件进行读写要健壮得多。如果有什么地方出了问题,你会把原作和迄今为止你所做的任何工作都藏起来。如果在此过程中出现任何问题,您当前的方法可能会将文件弄乱

    下面是一个示例,使用和一个
    with
    块来确保所有内容都已正确关闭,即使出现错误:

    from tempfile import NamedTemporaryFile
    from shutil import move
    
    input_file = "input.txt"
    output_file = "input.txt"
    
    seen_lines = set()
    
    with NamedTemporaryFile('w', delete=False) as output, open(input_file) as input:
        for line in open(input_file, "r"):
            sline = line.rstrip('\n')
            if sline not in seen_lines:
                output.write(line)
                seen_lines.add(sline)
    move(output.name, output_file)
    
    即使输入和输出名称相同,末尾的
    move
    也会正常工作,因为
    output.name
    保证与两者不同

    还要注意,我正在从集合中的每一行中剥离换行符,因为最后一行可能没有换行符

    Alt解决方案

    如果您不关心行的顺序,可以通过直接在内存中执行所有操作来简化流程:

    input_file = "input.txt"
    output_file = "input.txt"
    
    with open(input_file) as input:
        unique = set(line.rstrip('\n') for line in input)
    with open(output_file, 'w') as output:
        for line in unique:
            output.write(line)
            output.write('\n')
    
    你可以将其与

    with open(input_file) as input:
        unique = set(line.rstrip('\n') for line in input.readlines())
    with open(output_file, 'w') as output:
        output.write('\n'.join(unique))
    

    第二个版本执行完全相同的操作,但同时加载和写入所有内容。

    我相信这是实现您所需的最简单的方法:

    with open('FileName.txt', 'r+') as i:
        AllLines = i.readlines()
        for line in AllLines:
            #write to file
    

    使用列表理解和
    str.join
    set
    sorted
    ,尝试以下代码:

    input_file = "input.txt"
    output_file = "input.txt"
    seen_lines = []
    outfile = open(output_file, "w")
    infile = open(input_file, "r")
    l = [i.rstrip() for i in infile.readlines()]
    outfile.write('\n'.join(sorted(set(l,key=l.index))))
    outfile.close()
    

    只要我的两分钱,以防你碰巧会用Python3。它使用:

    • 一个可重用的
      Path
      对象,它有一个方便的
      write\u text()
      方法
    • 一个
      OrderedDict
      作为数据结构,以同时满足唯一性和顺序约束
    • 一个生成器表达式,而不是路径。读取文本()以节省内存


    打开文件两次,因为
    input\u file
    output\u file
    是相同的。第二次你以阅读的方式打开时,我认为这就是你的问题所在。所以你就不能写了。@busybear是的。以
    r+
    的形式打开您的文件,以同时读取和写入文件(它们都可以工作)。此操作的可能重复修复了问题,对于小输入文件是一个很好的解决方案,但请注意,对于大文件,由于通过
    可见行的线性搜索,这将非常缓慢(二次时间)。当我使用此代码时,我看到
    在输出中保留了两次对肮脏动物的更改
    。@Mark我测试了代码,但没有看到。您可以复制代码并重试吗?可能是您在键入时无意中犯了一些错误。等等,我想这是因为最后一行末尾有
    EOF
    ,所以它认为它不是重复的。我测试过了。如果最后一行是重复行,则由于
    EOF
    ,它始终保留该行。有办法吗?我在窗户旁边way@Mark也许会有帮助。我不能肯定。我使用的是Ubuntu。在这一点上,重新打开进行写作会简单得多。如果要删除行,文件中会留下一个尾部。问题是,如果有100000行以上的行,这种删除重复项的方法非常慢。有更好的办法吗?也仍然得到相同的错误。@Mark。对于这样的大小,您的I/O是瓶颈。“我怀疑你能做多少事情来加快速度。”马克。我已经提出了一个替代方案文件中的行已经按照我想要的顺序排列了,你的第二个版本会删除重复的行。如果有两个副本,则最上面的副本是不应删除的副本。@Mark。第二个版本将不会保留行的原始顺序。
    # in-place removal of duplicate lines, while remaining order
    import os
    from collections import OrderedDict
    from pathlib import Path
    
    filepath = Path("./duplicates.txt")
    
    with filepath.open() as _file:
        no_duplicates = OrderedDict.fromkeys(line.rstrip('\n') for line in _file)
    
    filepath.write_text("\n".join(no_duplicates))