Bash 从非常大的文本文件中删除重复对

Bash 从非常大的文本文件中删除重复对,bash,perl,awk,Bash,Perl,Awk,我有一个非常大的文本文件(很少GB),其格式如下: 1 2 3 4 3 5 3 6 3 7 3 8 3 9 文件已排序,并删除了双线。有重复的对像'2 1','4 3'相反的顺序,我想删除。有没有人能在资源非常有限的环境中用BASH、AWK、perl或任何类似的语言来解决这个问题?我无法加载整个文件并在值之间循环 要删除第二个数字小于第一个数字的行吗 perl -i~ -lane'print if $F[0] < $F[1]' file perl-i~-lane'print if$F[

我有一个非常大的文本文件(很少GB),其格式如下:

1 2
3 4
3 5
3 6
3 7
3 8
3 9

文件已排序,并删除了双线。有重复的对像'2 1','4 3'相反的顺序,我想删除。有没有人能在资源非常有限的环境中用BASH、AWK、perl或任何类似的语言来解决这个问题?我无法加载整个文件并在值之间循环

要删除第二个数字小于第一个数字的行吗

perl -i~ -lane'print if $F[0] < $F[1]' file
perl-i~-lane'print if$F[0]<$F[1]”文件

对于每个值,对硬盘上的文件执行二进制搜索,而不将其加载到内存中。如果看到副本,请将其删除。然后执行最后一步,删除两个或多个
\n

可能的解决方案的所有实例:

  • 扫描文件
  • 对于第二个值小于第一个值的任何对,交换两个数字
  • 按第一个数字再按第二个数字对这些对进行排序
  • 删除重复项
我仍在考虑更有效的磁盘扫描解决方案,但这是一种基本的天真方法

perl-lane'
perl -lane '
    END{
        print for sort {$a<=>$b} keys %h;
    }

    $key = $F[0] < $F[1] ? "$F[0] $F[1]" : "$F[1] $F[0]";
    $h{$key} = "";
' file.txt
结束{ 打印排序{$a$b}键%h; } $key=$F[0]<$F[1]?“$F[0]$F[1]”:“$F[1]$F[0]”; $h{$key}=“”; 'file.txt
解释

  • 我按数字顺序对当前行排序
  • 我通过将第一个值和第二个值与一个空格串联,来生成散列键变量
    $key
  • 我将
    $hash{$key}
    定义为nothing
  • 最后,我按数字顺序打印所有键
  • 哈希键本质上是uniq的,因此没有重复项

    您只需要使用
    Unix
    重定向来创建一个新文件。

    这里有一个通用的O(n)算法,可以在一个过程中完成此操作(无需循环或排序):

  • 以一个空的hashset作为黑名单开始(set是一个只包含键的映射)
  • 一次读取一行文件
  • 对于每一行:
    • 查看这双鞋是否已经在您的黑名单中
    • 如果是这样,忽略它
    • 如果没有,请将其附加到结果文件中;并将交换后的值添加到黑名单中(例如,如果您刚刚将“34”和“43”读到黑名单中)

  • 这需要O(n)个时间来运行,并且黑名单需要O(n)个存储。(如果您将文件作为r/w进行操作以在检查黑名单时删除行,则不会对结果进行额外存储)

    考虑到
    12
    21
    相同,是否要删除重复项

    < file.in \
    | perl -lane'print "@F[ $F[0] < $F[1] ? (0,1,0,1) : (1,0,0,1) ]"' \
    | sort -n \
    | perl -lane'$t="@F[0,1]"; print "@F[2,3]" if $t ne $p; $p=$t;' \
    > file.out
    
    文件输出
    

    这可以处理任意大的文件。

    不确定这是否有效/是否有用

    awk '{ if ($2 > $1) print; else print $2, $1 }' hugetext | sort -nu -O hugetext
    


    我不明白:你有重复的配对,你已经删除了重复的。。。这怎么可能?!你能解释一下吗?@ouki他的意思是他有1,2,然后是2,1,如果有必要,你能重新排序列表吗?如果是这样的话,我有一个解决方案。在第一次排序和删除文件中的DUP之前,如果第一个数字>第二个数字,您不能颠倒顺序吗?@user1297220,没有
    24
    ,是否可以获得
    42
    ?如果是,应该输出什么?他可能认为
    12
    等同于
    21
    ,如果出现
    12
    ,那么
    21
    也不应该出现。至少我是这样理解这个问题的。也许OP可以澄清一下。不,有很多对像and,我想删除它,我的代码就是这样做的。问题是您没有指定当您有1444122而没有1221444时应该发生什么。您没有指定任何新的内容。请澄清。@ikegami您的代码不会接受一个具有单个值{4,1}的文件而不输出任何内容吗?@platoali如果这解决了您的问题,请接受它作为答案。如何做?请你说得更具体一点好吗?这是个不错的主意,假设你们两人都很整齐。如果你有{1,2}你可以翻转它{2,1}用二进制搜索这个值,如果你找到它,就删除它。但这需要大量的磁盘查找。@Alan:如果OP没有内存将文件加载到内存中,我看不到一个不需要大量磁盘读写的解决方案。@ninjagecko我同意,我认为您可能有最好的方法,需要多少内存?;-)您是否需要将黑名单存储在内存中,这样做会比在磁盘上使用N^2循环结构更好?为了减少内存使用量,您只能存储$small,$more对,然后在比较之前将所有对转换为$small,$more格式。考虑到得分最高的答案,您可以使用
    awk'$1@Bernhard,我知道你的意思。但是OP说,“……这是行不通的,因为这对是不对称的”。不能保证它总是对称的。这将在内存中产生一个非常大的散列。当内存耗尽时,进程将被终止。我无法在内存中加载整个数据。“我无法加载整个文件并在值之间循环。”--OP@ninjagecko他不需要,他只需要一次扫描一行,听起来他已经能够排序和删除重复项了。我相信他的意思是,他不能将整个文件存储在内存中,以便更容易地检查重复的文件,但他如何在不将整个文件读入内存的情况下对文件进行排序?