【问题标题】:bash/awk: Getting largest value per cellbash/awk:获取每个单元格的最大值
【发布时间】:2015-02-25 02:07:35
【问题描述】:

我有一个制表符分隔的文件A,如下所示:

seqnameAa_len_240                     seqnameBa_len_247
seqnameAb_len_881                     seqnameBb_len_719
seqnameAc_len_736,seqnameAd_len_640   seqnameBc_len_489
seqnameAe_len_241                     seqnameBd_len_302,seqnameBe_len_465
seqnameAf_len_436,seqnameAf_len_620   seqnameBf_len_452,seqnameBg_len_435

左边的序列来自一个数据集,右边的序列来自另一个。每行反映一组相似的序列。在某些情况下,来自一个、另一个或两个数据集的多个序列属于同一序列组(反映在一列中用逗号分隔的多个序列)。

对于每一行,我想找到一种方法来找到两个数据集的最大值,并给出以下输出。

240    247
881    719
736    489
241    465
620    452

我想过在所有行上创建一个 for 循环,然后为每一行用换行符替换逗号,然后删除所有文本并保留数字并使用 awk 选择每列的最大值。但是根据我目前的 bash/awk 知识,必须按列完成,并且每个单元格没有固定数量的逗号分隔条目,我不知道该怎么做。

有没有更简单的方法从 fileA 获取上述输出?

【问题讨论】:

  • 不要犹豫,尝试自己编写代码并展示您的尝试。否则,您很可能会习惯于完成任务,而当您需要自己完成任务时,您将一无所获。

标签: bash unix awk


【解决方案1】:
$ cat tst.awk
BEGIN { FS=OFS="\t" }
{
    for (fldNr=1; fldNr<=NF; fldNr++) {
        split($fldNr,fldArr,/,/)
        for (sfNr=1; sfNr in fldArr; sfNr++) {
            sub(/.*_/,"",fldArr[sfNr])
            max = ( (sfNr==1)||(fldArr[sfNr]>max) ? fldArr[sfNr] : max)
        }
        $fldNr = max
    }
    print
}

$ awk -f tst.awk file
240     247
881     719
736     489
241     465
620     452

【讨论】:

    【解决方案2】:
    perl -MList::Util=max -lane '
        print max($F[0] =~ /\d+/g), "\t", max($F[1] =~ /\d+/g)
    ' fileA
    

    【讨论】:

    • 虽然这段代码 sn-p 可以解决问题,但including an explanation 确实有助于提高帖子的质量。请记住,您是在为将来的读者回答问题,而这些人可能不知道您提出代码建议的原因。
    【解决方案3】:

    我会使用一些笨拙的技巧来实现这一点,而无需手动拆分:

    gawk -F , -v RS='[\t\n]' '{ m = 0; for(i = 1; i <= NF; ++i) { sub(/.*_/, "", $i); if($i > m) { m = $i } } printf m RT }'
    

    诀窍是使用制表符和换行符作为记录分隔符,这样记录就不再是一行,而是一个字段(例如seqnameAf_len_436,seqnameAf_len_620),字段$1$2 和等等是以逗号分隔的子字段(因为-F ,)。那么

    {
      m = 0
      for(i = 1; i <= NF; ++i) { # walk through the (comma-delimited) fields 
        sub(/.*_/, "", $i)       # isolate the number
        if($i > m) {             # find the maximum
          m = $i
        }
      }
      printf m RT                # and print it with the same record terminator
                                 # that was in the input (tab or newline)
    }
    

    使用正则表达式作为记录分隔符和 RT 都是 gawk 特有的。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2010-10-19
      • 1970-01-01
      • 1970-01-01
      • 2017-04-19
      • 2021-07-20
      • 2021-09-15
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多