【问题标题】:How to compare lines with the same unique substring in one field and keep only those lines with the largest number in the last field?如何比较一个字段中具有相同唯一子字符串的行并仅保留最后一个字段中具有最大数字的行?
【发布时间】:2021-03-21 21:57:40
【问题描述】:

我有一个文件,其格式为一系列唯一标识符 (>lcl|ORF#_URS[:alnum:]:##:## foo, bar:##) 段,紧跟其下的一行是相应的 alpha 字符串 (ALPHAALPHAALPHA:::0)。 文件示例:

>lcl|ORF1_URS0000000001:102:197 unnamed protein product:95
MVVGDNARKRTLIPHTSYGRKQGTFGPCAIR:::0
>lcl|ORF2_URS0000000001:1:93 unnamed protein product, partial:92
LNAGGRPNTCKSSGREKLASLESGGRVSNA:::0
>lcl|ORF3_URS0000000001:8:82 unnamed protein product:74
MAAGLTHASRAVERSLLLLRAADG:::0
>lcl|ORF4_URS0000000001:86:118 unnamed protein product:32
MPRNLPGSGG:::0
>lcl|ORF5_URS0000000001:193:152 unnamed protein product:41
MIAQGPKVPCFLP:::0
>lcl|ORF6_URS0000000001:167:135 unnamed protein product:32
MLSPVGRMRY:::0
>lcl|ORF7_URS0000000001:32:0 unnamed protein product, partial:32
MHVLGLPPAFN:::0
>lcl|ORF1_URS00000000M3:42:77 unnamed protein product:35
MINALCSYLLA:::0
>lcl|ORF2_URS00000000M3:174:236 unnamed protein product:62
MRGRSPTLVLRHGPDFYGRQ:::0
>lcl|ORF3_URS00000000M3:246:311 unnamed protein product:65
MDNGGNSDPAMPREGRRPYGL:::0

解决此问题需要重点关注的关键元素是字母数字 URS 标识符 和以 ">"$4) /strong> 并由 ":" 分隔。

我想只保留每个 唯一 字母数字 URS 标识符(例如,URS0000000001URS00000000M3 等)与 最大值 的行同一行的最后一个字段(始终以“>”开头并以“:”分隔)。如果同一标识符的最终字段中有两行或多行具有相同值,则取第一行或最后一行(无关紧要)。 所需输出示例:

>lcl|ORF1_URS0000000001:102:197 unnamed protein product:95
>lcl|ORF3_URS00000000M3:246:311 unnamed protein product:65

OR 如果它更简单:

URS0000000001    95
URS00000000M3    65

这远远超出了我对awk 的能力,但我觉得我的逻辑已经完成了一半。我尝试编写一个awk 命令,该命令将搜索以“>”开头的每一行,并在 $4 大于 $4 时在具有相同 URS 标识符的另一行上打印该行:

awk -F":" 'BEGIN {OFS=FS} /^ *>/ {if (substr($1,11)==substr($1,11)){$4>$4}} 1' file

必须有更好的方法来匹配不同行上字段 ($1) 的 子字符串,以便随后将链接/关联字段 ($4) 与 awk 进行比较。想法?

【问题讨论】:

  • 所以基本上,对于您想要的每个 URS 以及该行末尾的最大数字?
  • @MarkSetchell Bingo。你明白了。

标签: awk


【解决方案1】:

请您尝试以下方法:

awk -F ":" '
    NR==FNR {                                   # 1st loop to find the maximum valued line for each id
        if (match($1, "URS[[:alnum:]]+")) {     # check if $1 matches the format
            id = substr($1, RSTART, RLENGTH)    # extract the id
            if ($4 > a[id]) {                   # if $4 > max
                a[id] = $4                      # update the max value
                b[id] = $1                      # memorize the corresponding $1
            }
        }
        next
    }
    {                                           # 2nd loop to print the maximum valued line for each id
        if (match($1, "URS[[:alnum:]]+")) {
            id = substr($1, RSTART, RLENGTH)
            if ($1 == b[id]) print
        }
    }
' file file

输出:

>lcl|ORF1_URS0000000001:102:197 unnamed protein product:95
>lcl|ORF3_URS00000000M3:246:311 unnamed protein product:65

如果更简单的输出足够好并且你不介意出现的顺序,一个更简单的替代方案:

awk -F ":" '
    NR==FNR {
        if (match($1, "URS[[:alnum:]]+")) {
            id = substr($1, RSTART, RLENGTH)
            if ($4 > a[id]) a[id] = $4
        }
        next
    }
    END {
        for (i in a) print i, a[i]
    }
' file

输出:

URS00000000M3 65
URS0000000001 95

【讨论】:

  • 感谢您尝试这个棘手的问题。不幸的是,这两个脚本都给了我一个空的输出文件。你知道我做错了什么吗?
  • 感谢您的反馈。我不知道是什么问题,但我听说某些平台不接受正则表达式字符类,例如[[:alnum:]]。您是否将match() 函数中的第二个参数"URS[[:alnum:]]+" 替换为"URS[0-9A-Za-z]+" 作为尝试。
  • 非常感谢! 您的建议适用于第二个脚本。 奇怪的是,它似乎不适用于第一个脚本,但只要其中一个对我有用,我就很高兴。再次感谢。
猜你喜欢
  • 2019-09-09
  • 2011-02-14
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-04-03
  • 1970-01-01
相关资源
最近更新 更多