【问题标题】:awk combine sequence with substring keyawk 将序列与子字符串键组合起来
【发布时间】:2016-09-01 07:45:50
【问题描述】:

我有两个文件用于与制表符分隔文件组合。 这两个文件键可能仅对于“读取”数不同。

我想比较这两个文件并根据子字符串键和匹配进行组合。

例如,

File1 Key : "Cluster0_Reads255" 
File2 Key : "Cluster0_Reads50"
This case is same because "Cluster0_Reads" is identical.

这种情况下,我想将这两列与 File1 键名结合起来。 请查看以下示例。

文件 1。

       A                B             
Cluster0_Reads255      500
Cluster1_Reads253      300
Cluster2_Reads100      200
Cluster3_Reads100      350

文件 2。

        A               C          
Cluster0_Reads50       GE
Cluster1_Reads200      GA
Cluster2_Reads100      GA

结果。

       A                B       C            
Cluster0_Reads255      500     GE
Cluster1_Reads253      300     GA
Cluster2_Reads100      200     GA
Cluster3_Reads100      350     -

我做了一个 awk 与完全匹配查找和组合,如下所示,

awk '
BEGIN { FS = OFS = "\t" }
{key = $1}
FNR == NR {result[key] = $0; next;}
(key in result) { updated[key]=1 ; for (i=2; i <= NF; i++) result[key] = result[key] FS $i }
END {
    PROCINFO["sorted_in"] = "@ind_str_asc"    # if using GNU awk
    for (key in result) {
            if(!(key in updated)) result[key] = result[key] FS "-"
            if(!(length(key)==0)) print result[key]
    }
}
' File1 File2 > File3

有没有什么办法可以在子串之后进行组合?

谢谢。

【问题讨论】:

  • 您的示例输入似乎在第一列(集群 0、1、2、3)中排序。如果这是真的,您可以执行类似 paste t1 &lt;(awk '{print $2}' t2) | perl -pe 's/^(\S+[ \t]+){2}$/$&amp;-/' 的操作

标签: linux bash awk


【解决方案1】:

下面有点脏 awk 脚本可以完成这项工作,但我相信你会找到更好的。

awk -v FS="\t" -v OFS="\t" '
NR==FNR{f1=$1;sub(/[0-9]*$/,"",f1);file1info[f1]=$0;next}
       {sub(/[0-9]*$/,"",$1);file2info[$1]=$2}
    END{
        for(i in file1info){
        print file1info[i],(i in file2info)?file2info[i]:"-";
        }
       }' File1 File2 | expand -t 20 | sort -nk1

输出

A                   B                   C          
Cluster0_Reads255   500                 GE
Cluster1_Reads253   300                 GA
Cluster2_Reads100   200                 GA
Cluster3_Reads100   350                 -

编辑

终于找到了一个更小更快的。考虑到 file2 的集群总是形成 file1 的子集,诀窍是反转文件。

awk -v FS="\t" -v OFS="\t" '
NR==FNR{sub(/[0-9]*$/,"",$1);file2info[$1]=$2;next}
       {f1=$1;sub(/[0-9]*$/,"",f1);print $0,(f1 in file2info)?file2info[f1]:"-"}
       ' File2 File1   | expand -t 20 |sort -nk1

输出

A                   B                   C          
Cluster0_Reads255   500                 GE
Cluster1_Reads253   300                 GA
Cluster2_Reads100   200                 GA
Cluster3_Reads100   350                 -

【讨论】:

  • 解决方案 2 特别好 :) +1
  • @clear.choi :我对此表示怀疑,但感谢您的确认 :)
【解决方案2】:

在 Gnu AWK 中:

$ cat > do.awk
FNR==NR {
    a[gensub(/[0-9]+$/,"","g",$1)]=$0         # remove nums from end of index
    next 
} 
(i=gensub(/[0-9]+$/,"","g",$1)) && (i in a) { # if match in a
    sub(/\t/,OFS $2 OFS,a[i])                 # change order
    $0=a[i]
} 1                                           # print
$ awk -v OFS="\t" file2 file1
A       B       C
Cluster0_Reads50        500     GE
Cluster1_Reads200       300     GA
Cluster2_Reads100       200     GA
Cluster3_Reads100       350

【讨论】:

    【解决方案3】:
    $ cat tst.awk
    BEGIN { FS=OFS="\t" }
    { key=$1; sub(/[0-9]+$/,"",key) }
    NR==FNR { map[key]=$2; next }
    { print $0, (key in map ? map[key] : "-") }
    
    $ awk -f tst.awk file2 file1
    A       B       C
    Cluster0_Reads255       500     GE
    Cluster1_Reads253       300     GA
    Cluster2_Reads100       200     GA
    Cluster3_Reads100       350     -
    
    $ awk -f tst.awk file2 file1 | column -s$'\t' -t
    A                  B    C
    Cluster0_Reads255  500  GE
    Cluster1_Reads253  300  GA
    Cluster2_Reads100  200  GA
    Cluster3_Reads100  350  -
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2021-04-08
      • 1970-01-01
      • 1970-01-01
      • 2023-01-09
      • 2011-08-02
      • 2023-03-22
      • 1970-01-01
      相关资源
      最近更新 更多