【问题标题】:Print whole lines, when find duplicate当发现重复时打印整行
【发布时间】:2021-01-02 16:39:50
【问题描述】:

这是我输入的片段:

DGD3 SOL10
DGD53 SOL15
DGD100 SOL15
DGD92 SOL20
DGD41 SOL22
DGD62 SOL35
DGD13 SOL40
DGD13 SOL40

我的预期输出

DGD53 SOL15
DGD100 SOL15
DGD13 SOL40
DGD13 SOL40

在我的数据中,有时 SOL 重复(不超过两次重复,例如文件中某些 SOL 的三倍,但仅重复)。 SOL 在我的第二列 ($2) 中。因此,当我发现重复的 SOL($2)时,我需要一个打印整行(DGD 和 SOL)的程序。你能帮帮我吗?

【问题讨论】:

  • 副本是否总是彼此相邻,或者它们可以在文件中的任何位置?
  • 可以在任何地方
  • 使用 GNU uniq:uniq -f 1 -D file

标签: awk data-processing


【解决方案1】:

以 awkish 风格添加另一种方式,在第一次读取 Input_file 时获取所有值计数,并在第二次读取时根据它们的计数打印所有值。公平警告这可能不像其他 2 种解决方案那样快,但从理解的目的来看应该很简单。

awk '
FNR==NR{
  count[$2]++
  next
}
(count[$2]>1)
' Input_file  Input_file

【讨论】:

    【解决方案2】:

    另一个 awk。单次运行,不需要对文件进行排序,如果第二个字段的实例超过 2 个,则可以正常工作。在最坏的情况下,它会对内存中的完整文件进行哈希处理,并且不会产生任何输出:

    $ awk '{
        if(!c[$2]++)           # if first instance of $2
            a[$2]=$0           # store it
        else {
            if(c[$2]==2) {     # if second instance 
                print a[$2]    # print previous
                delete a[$2]   # no need to waste my memory any more
            } 
            print              # after first instance of $2 we always print current
        }
    }' file
    

    输出:

    DGD53 SOL15
    DGD100 SOL15
    DGD13 SOL40
    DGD13 SOL40
    

    【讨论】:

      【解决方案3】:

      您可以使用此awk,它将打印重复的不一定是相邻的:

      awk '$2 in map {print map[$2] ORS $0} {map[$2] = $0}' file
      
      DGD53 SOL15
      DGD100 SOL15
      DGD13 SOL40
      DGD13 SOL40
      

      【讨论】:

        【解决方案4】:

        如图所示(按第二个字段排序),您可以执行以下操作:

        $ awk 'l2==$2{print ll; print; next}
               {ll=$0; l2=$2}' file
        

        打印:

        DGD53 SOL15
        DGD100 SOL15
        DGD13 SOL40
        DGD13 SOL40
        

        这类似于仅打印相邻重复项的 Unix uniq 过滤器。

        如果文件中的重复是随机的,您可以先排序:

        $ awk 'l2==$2{print ll; print; next}
                    {ll=$0; l2=$2}' <(sort -k 2 file) 
        

        或者,对文件进行两次遍历:

        $ awk 'FNR==NR{cnt[$2]++; next} cnt[$2]>1' file file
        

        或者,要识别 2 个或更多的 SOL 标签,您可以这样做:

        $ awk '++cnt[$2]==2' file   
        

        您可以使用相同的方法生成命令代码到grep 或sed 以从未排序的文件中打印:

        $ sed -n -f <(awk '++cnt[$2]==2 {printf "/[[:space:]]%s$/p\n", $2}' file) file
        

        所以选择是:

        1. 使用更多内存(通过将整个文件缓存在以$2 为键的内存中),或者
        2. 先排序,或者
        3. 遍历文件两次。

        【讨论】:

          【解决方案5】:

          如果您的文件在第二个字段中排序,uniq 是为此任务而设计的,具有正确的选项。

          $ uniq -f1 -D file
          
          DGD53 SOL15
          DGD100 SOL15
          DGD13 SOL40
          DGD13 SOL40
          

          跳过第一个字段,打印所有重复项...

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 1970-01-01
            • 2017-12-01
            • 1970-01-01
            • 1970-01-01
            • 2011-07-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            相关资源
            最近更新 更多