bash/awk:获取每个单元格的最大值
bash/awk: Getting largest value per cell
我有一个制表符分隔的文件 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 循环,然后为每一行用换行符替换逗号,然后删除所有文本并只保留数字和 select 每列的最大值哇哦。但是根据我目前的 bash/awk 知识,必须按列完成,并且每个单元格没有固定数量的逗号分隔条目,我不确定该怎么做。
是否有更简单的方法从文件 A 获取上述输出?
perl -MList::Util=max -lane '
print max($F[0] =~ /\d+/g), "\t", max($F[1] =~ /\d+/g)
' fileA
我会使用一些 gawk 技巧来实现这一点,而无需手动拆分:
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
),字段</code>, <code>
等等是逗号分隔的子字段(因为 -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 的。
$ 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
我有一个制表符分隔的文件 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 循环,然后为每一行用换行符替换逗号,然后删除所有文本并只保留数字和 select 每列的最大值哇哦。但是根据我目前的 bash/awk 知识,必须按列完成,并且每个单元格没有固定数量的逗号分隔条目,我不确定该怎么做。
是否有更简单的方法从文件 A 获取上述输出?
perl -MList::Util=max -lane '
print max($F[0] =~ /\d+/g), "\t", max($F[1] =~ /\d+/g)
' fileA
我会使用一些 gawk 技巧来实现这一点,而无需手动拆分:
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
),字段</code>, <code>
等等是逗号分隔的子字段(因为 -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 的。
$ 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