如何使用awk进行连接

时间:2015-10-26 18:12:36

标签: awk

这是我的输入文件

Identifier Relation
A           1
A           2
A           3
B           2
B           3
C           1
C           2
C           3

我想基于"关系"将此文件加入到自身中。领域。 示例输出文件

A 1 C 1
A 2 B 2
A 2 C 2
B 2 C 2
A 3 B 3
A 3 C 3
B 3 C 3

我使用了以下awk脚本: awk 'NR==FNR {a[NR]=$0; next} { for (k in a) if (a[k]~$2) print a[k],$0}' input input > output

但是,我必须做另一个awk步骤来删除与其自身连接的行,即A 1 A 1; B 2 B 2等。

此文件的第二个问题是它会打印连接的两个方向 在另一条线上印刷1 C 1和C 1 A 1。 这两行显示相同的关系,我不想包括这个。我想看到其中一个,即" A 1 C 1"或" C 1 A 1"不是都。 任何建议/方向都非常感谢。

3 个答案:

答案 0 :(得分:2)

使用带有连接和排序支持的awk的替代解决方案

$ join -j 2 <(sort -k2 -k1,1 file){,} 
| awk '$2!=$3 && !($3 FS $2 in a){a[$2 FS $3]; print$2,$1,$3,$1}'
A 1 C 1
A 2 B 2
A 2 C 2
B 2 C 2
A 3 B 3
A 3 C 3
B 3 C 3

创建交叉积,消除对角线和其中一对对称。

答案 1 :(得分:1)

肯定只有awk的解决方案,但我会提出一个使用awk和sort的解决方案,因为我认为这很简单,并且不需要将整个文件内容存储在awk变量中。这个想法如下:

  • 重写输入文件,以便首先显示“关系”字段(A 1 - &gt; 1 A
  • 使用sort -n将所有具有相同“关系”的行放在一起
  • 使用awk组合具有相同“关系”的连续行

这会转化为:

awk '{print $2 " " $1}' input | sort -n | 
  awk '{if ($1==lastsel)printf " "; else if(lastsel) printf "\n"; lastsel=$1; printf "%s %s", $2, $1;}END{if(lastsel)printf"\n"}'
A 1 C 1
A 2 B 2 C 2
A 3 B 3 C 3

编辑:如果每行只需要一个i-j关系:

awk '{print $2 " " $1}' input | sort -n |
  awk '$1!=rel{rel=$1;item=$2;next;} {printf "%s %s %s %s\n", item, rel, $2, $1;}'
A 1 C 1
A 2 B 2
A 2 C 2
A 3 B 3
A 3 C 3

请注意此解决方案的以下限制:

  • 如果给定的n只有一个条目,则不会输出任何内容(没有输出,例如D 1
  • 所有关系在第一列中始终具有按字典顺序排列的第一项(例如A 1 C 1但从不B 1 C 1

答案 2 :(得分:1)

这是一个仅支持awk的解决方案:

awk 'NR>1{ar[$2]=(ar[$2]$1);}\
    END{ for(key in ar){\
        for(i=1; i<length(ar[key]); i++) {\
            for(j=i+1; j<length(ar[key])+1; j++) {\
                print substr(ar[key],i,1), key, substr(ar[key],j,1), key;\
            }\
        }\
    }}' infile

input第二列中的每个数字都用作awk数组的键。相应数组元素的值是第一列字母序列(例如,数组[1] = ABC)。

然后,我们为每个序列构建了所有双字母组合(例如,“ABC”给出“AB”,“AC”和“BC”)

输出:

A 1 C 1
A 2 B 2
A 2 C 2
B 2 C 2
A 3 B 3
A 3 C 3
B 3 C 3

注意:

  • 如果一个数字只出现一次,则不会为此数字生成输出。
  • 输出顺序取决于输入顺序。 (没有字母排序!!)。也就是说,如果第二个输入行是C 1,那么array[1]="CAB",第一个输出行将是C 1 A 1
  • 由于NR>1
  • ,第一行输入被忽略