2013-04-30 85 views
0

我需要删除文件中多次出现的所有行。删除重复的行(包括重复的行)

实施例:

Line1 
Line2 
Line3 
Line2 

结果:

Line1 
Line3 

Python和Perl或UNIX的UTIL,无所谓。谢谢。

+0

您是否需要保留原始订单? – abarnert 2013-04-30 17:05:58

+0

这个问题已经回答了几次;检查[this] [1]。 [1]:http://stackoverflow.com/questions/1215208/how-might-i-remove-duplicate-lines-from-a-file – 2013-04-30 17:06:26

+0

否的顺序并不重要。 – tor11 2013-04-30 17:08:52

回答

2

这是一个Python实现。

如果您需要保存线的初始订单:

import collections 
import fileinput 

lines = list(fileinput.input()) 
counts = collections.Counter(lines) 
print(''.join(line for line in lines if counts[line] == 1)) 

如果不是,它是一点点简单和快速):

import collections 
import fileinput 

counts = collections.Counter(fileinput.input()) 
print(''.join(line for line, count in counts.iteritems() if count==1)) 

对于每一行,你需要看如果它有任何dups。如果您不希望以二次方式执行此操作(执行一次传递,然后再执行每一行的第二次传递),则需要使用中间数据结构,该结构允许您以两次线性传递完成此操作。

所以,你通过列表​​来构建一个散列表(collections.Counter是一个专门的dict,只是将每个键映射到它出现的次数)。然后,您可以在列表中进行第二遍,在散列表(第一个版本)中查看每一个,或者迭代散列表(第二个)。


据我所知,没有办法与命令行工具做等价的事情;你至少需要输入sort(它是O(N log N),而不是O(N)),或者使用一个隐式执行等价操作的工具。

但是对于很多用例来说,这不是什么大不了的事情。对于具有1M行的80MB文件,N log N仅比N慢一个数量级,并且完全可以想象,两个工具之间的常数乘数差异将是相同的。


快速计时测试验证,在1M的线路规模,sort | uniq -u版本是刚刚超过6倍的速度较慢,但​​仍然不够快,你可能不会关心(不足10秒,这是更多的时间比复制和粘贴Python代码要复杂得多,对吧?),除非您必须重复执行此操作。

从进一步的测试,在128K行,Python版本只有4倍的速度;在64M线上,速度提高了28倍;在5G线...两个版本驱动系统进入交换抖动足够严重,我杀死了测试。 (更换Counterdbm键值数据库解决了这个问题,但对于小规模巨大的成本。)

+0

对不起,我忽略了关于测试的一点。评论撤回。 – ikegami 2013-04-30 19:35:47

1

的* nix的命令uniq的可以做到这一点。

sort file.name | uniq -u 
+0

不,它不能。这将包括第一次出现的“Line2”,OP明确不需要。即使他不想要这样,'uniq'也需要对数据进行排序,但事实并非如此。 – abarnert 2013-04-30 17:14:58

+1

添加'-u'不能解决任何问题。这只是默认值(与'-d'相反)。你甚至尝试过吗? – abarnert 2013-04-30 17:18:23

+0

@abarnert:也许你有一个不太能干的uniq – ysth 2013-04-30 17:19:47

-1

读每一行,用grep线在同一文件中找到的计数,仅打印那些其中计数为1:

#!/bin/bash 
while read line 
do 
    if [ `grep -c ${line} sample.txt` -eq 1 ] ; then echo ${line} ; fi 
done < sample.txt 
+0

这有效,但它是二次的:每行重新读取整个文件一次。对于大文件来说,这是一个非常糟糕的主意。 – abarnert 2013-04-30 17:21:28

+0

... done <'uniq sample.txt' – Bill 2013-04-30 17:35:17

+0

'uniq'在没有'sort'的情况下不会产生任何有用的效果 - 即使有了它,它仍然是一个二次方案,并且它不会在“sort”和“uniq”已经可以自己给你了。 – abarnert 2013-04-30 17:36:34

0
sort inputfile | uniq -u 

(假设GNU的coreutils的uniq)

虽然SUSv4说:

-u 禁止写入输入中重复的行。

它听起来从一些答案,并非所有的uniqs解释相同的方式。

+0

谢谢大家,我试过你的解决方案,这似乎是最简单的一个,为我工作(Debian 2.6.32) – tor11 2013-04-30 17:37:51

1

下面是perl的一个例子:

my %line_hash; 
open my $fh, "<", "testfile"; 
while(my $line = <$fh>) { 
    $line_hash{$line}++; 
} 
close $fh; 

open my $out_fh, ">>", "outfile"; 
for my $key (sort keys %line_hash){ 
    print $out_fh $key if $line_hash{$key} == 1; 
} 
close $out_fh; 

testfile的:

$ cat testfile 
Line1 
Line2 
Line3 
Line2 

OUTFILE:

$ cat outfile 
Line1 
Line3 
4

果脯秩序,但保留在内存中的文件的两个副本:

my @lines; 
my %seen; 
while (<>) { 
    push @lines, $_; 
    ++$seen{$_}; 
} 

for (@lines) { 
    print if $seen{$_} == 1; 
} 

作为一个班轮:

perl -ne'push @l, $_; ++$s{$_}; }{ for (@l) { print if $s{$_} == 1; }' 

不维持秩序,但保存在内存只有一个文件的副本:

my %seen; 
++$seen{$_} while <>; 

while (my ($k, $v) = each(%seen)) { 
    print $k if $v == 1; 
} 

作为一个班轮:

perl -ne'++$s{$_}; }{ while (my ($k, $v) = each(%s)) { print $k if $v == 1; }' 
+0

从一个快速测试,这些似乎工作。扫描代码,它们在功能上与我的两个Python实现完全相同,大小相同,速度+/- 50%,内存使用类似。据推测,对于熟悉Perl但不熟悉Python的人来说,它会更易读,并且从快速测试中看来似乎可行。所以... +1。您可能想要阅读其他perl的答案,因为我不确定它是否相同。 (我很早以前就故意用电极烧掉我的大脑中读取perl的那部分内容。) – abarnert 2013-04-30 18:07:48

+0

@abarnert,是的,它实际上非常干净的Perl代码,但Perl看起来与其他语言有点不同,所以它可能很难读给外人看。 ///我看到了另一个Perl的答案。它使用尽可能多的内存作为我的订单保存解决方案,但它不能保持顺序。 (它也可以分类,尽管它只是出于美学原因,所以如果性能是一个问题,它可以被删除。) – ikegami 2013-04-30 19:43:01