gawk 按列连接两个 TSV(a'la sql 连接)

gawk 按列连接两个 TSV(a'la sql 连接)

如何加入 tsv 文件,示例:

TSV

c   7   r   z
d   6   s   w
f   1   f   f
b   8   p   y
a   9   q   x

tsv

a   q   a
c   r   ccc
b   p   bb
0   0   0
d   s   dddd

在这里,我想按列“加入”它们,where a$1,a$3==b$1,b$2并显示其余 (a$2,a$4,b$3) :

6   w   dddd
9   x   a
8   y   bb
7   z   ccc

问题是:你会如何在 gawk 中做到这一点?

行的顺序不符合要求(在输出中。在输入中,行的顺序未定义,并且在 a.tsv 和 b.tsv 中可以不同 - 就像关系数据库中的行一样,它们没有顺序)。

唯一性说明:最初,我假设“ key={a$1,a$3}.As的唯一性”格伦·杰克曼注意到 - 不能从原始问题陈述中假设,因为它不允许根据任何键的唯一行 - 谢谢格伦

答案1

看来该join命令只能加入一个字段 [1,2], 所以:

awk '
    BEGIN {FS=OFS="\t"}
    NR==FNR {a[$1 FS $3] = $2 FS $4; next}
    $1 FS $2 in a {print a[$1 FS $2], $3}
' a.tsv b.tsv

由于评论而更新:由于给定的密钥不是唯一的,因此这里有一种从“a.tsv”构建多个条目的技术

awk '
    BEGIN {FS=OFS="\t"}
    NR==FNR {
        key = $1 FS $3
        if (key in a)
            a[key] = a[key] "\n" $2 FS $4
        else
            a[key] = $2 FS $4
        next
    }
    $1 FS $2 in a {
        split(a[$1 FS $2], ary, /\n/)
        for (idx in ary)
            print ary[idx], $3
    }
' a.tsv b.tsv

答案2

我将任务分成两个不同的程序:

  1. 使用加入(1)连接两个文件

  2. awk(1)或者切割(1)去除不需要的列

答案3

我不太清楚awk,但它是专门为处理文本文件中的字段而设计的,所以我认为它可以很好地完成这项工作,但因为你似乎(?)表达了对join(在ktf的评论),这里是一个使用标准 unix 工具的解决方案:joinand cutand pasteand sort-- 很多“and”,但它有效并且可以作为为什么awk更好的一个例子:)...我把它主要是为了然后是方法比较因素。

join -t $'\t' -o 1.2 1.3  2.2  \
 <(paste <(paste <(cut -f1 a.tsv) \
                 <(cut -f3 a.tsv) \
                 | tr '\t' '\0' ) \
         <(cut -f2 a.tsv) \
         <(cut -f4 a.tsv) \
         | sort ) \
 <(paste <(paste <(cut -f1 b.tsv) \
                 <(cut -f2 b.tsv) \
                 | tr '\t' '\0' ) \
         <(cut -f3 b.tsv) \
         | sort ) 

答案4

最后我成功做到了。所以我分享我的解决方案:

awk '
BEGIN {
    FS=OFS="\t"
    while ((getline < "a.tsv") > 0){
        a2[$1,$3] = $2; a4[$1,$3] = $4
    }
}
($1,$2) in a2 { print a2[$1,$2] FS a4[$1,$2] FS $3 }' < b.tsv

产生:

9   x   a
7   z   ccc
8   y   bb
6   w   dddd

这个解决方案:

  • 不假设输入行的顺序
  • 当某些行在其他文件中没有匹配时有效
  • 假设中的行a.tsv是唯一的key = {a$1,a$3}

对于那些感兴趣的人右连接,你只需要删除if( ($1,$2) in a2)语句即可。对于那些感兴趣的人左连接,只需执行“右连接”版本并将 a.tsv 与 b.tsv 交换(并相应地更改代码)。

唯一性说明: 作为格伦·杰克曼注意到,a.tsv根据 ,该行可能不是唯一的key={a$1,a$3},您可能想查看他的解决方案。

相关内容