我有两个文件,如下所示,以制表符分隔:
档案A
chr1 123 aa b c d
chr1 234 a b c d
chr1 345 aa b c d
chr1 456 a b c d
....
档案B
xxxx abcd chr1 123 aa c d e
yyyy defg chr1 345 aa e f g
...
我想基于2列使用“chr1”,“123”加入这两个文件,并将文件B中的前两列添加到文件A.这是使用
完成的。awk 'NR==FNR{a[$3,$4]=$1OFS$2;next}{$7=a[$1,$2];print}' OFS='\t' fileb filea
输出:
chr1 123 aa b c d xxxx abcd
chr1 234 a b c d
chr1 345 aa b c d yyyy defg
chr1 456 a b c d
然而,对于真实数据,fileb太大并且它返回错误:“无法分配6400字节的内存(无法分配内存)”。有人可以提供替代方法,以便以较小的部分读取文件。
答案 0 :(得分:3)
这为记忆交换速度:
$ cat tst.awk
BEGIN{
FS=OFS="\t"
lookup = ARGV[--ARGC]
delete ARGV[ARGC]
}
{
found = 0
while ( !found && ((getline str < lookup) > 0) ) {
split(str,arr)
if ( ($1 == arr[3]) && ($2 == arr[4]) ) {
$0 = $0 OFS arr[1] OFS arr[2]
found = 1
}
}
close(lookup)
print
}
$ gawk -f tst.awk fileA fileB
chr1 123 aa b c d xxxx abcd
chr1 234 a b c d
chr1 345 aa b c d yyyy defg
chr1 456 a b c d
它使用接近零的内存,因为它不会在内部存储任何值,但它会很慢,因为fileA中的每一行都会读取fileB中的每一行,直到找到匹配为止,而不是你已经尝试过的是从fileB读取所有行并将它们存储为由字段3和4键入的数组元素,在这种情况下,它将是fileA的每一行的内部哈希查找,而不是外部线性搜索。
如果fileB中存在许多不存在于fileB中的键,则可以通过在第3和第4个字段上排序fileB然后将getline循环中的测试更改为以下内容来显着加快速度:
if ( ($1 FS $2) == (arr[3] FS arr[4]) ) {
$0 = $0 OFS arr[1] OFS arr[2]
found = 1
}
else (if ($1 FS $2) < (arr[3] FS arr[4]) ) {
found = 1
}
你可以找出正确的逻辑 - 希望你能够在你已经超过你要从fileA查找的值可能存在于已排序的fileB中的点时停止循环。< / p>
答案 1 :(得分:1)
快速而肮脏的技巧是操纵输入数据并使用join
:
$ awk '{print $3"-"$4,$1,$2}' fileb | sort > fileb2
$ awk '{print $1"-"$2,$3,$4,$5}' filea | sort > filea2
$ join -a1 filea2 fileb2
chr1-123 aa b c xxxx abcd
chr1-234 a b c
chr1-345 aa b c yyyy defg
chr1-456 a b c
如有必要,您可以在第一列中删除 - 。请注意,这不是很强大,购买可能就足够了。 join
可能需要的内存少于awk
并且能够处理输入...或者它可能不会!
答案 2 :(得分:0)
您可以尝试以下代码:
#!/usr/bin/awk -f
BEGIN {
file1 = ARGV[1]
file2 = ARGV[2]
LIMIT = 1000
OFS = "\t"
i = 0
while ((getline < file2) > 0) {
key = $3 "\x1c" $4
if (!(key in a)) {
a[key] = $1 OFS $2
if (i == LIMIT) {
break
}
}
}
while ((getline < file1) > 0) {
key = $1 "\x1c" $2
if (key in a) {
$7 = a[key]
print
delete a[key]
while ((getline < file2) > 0) {
key = $3 "\x1c" $4
if (!(key in a)) {
a[key] = $1 OFS $2
break
}
}
} else {
$7 = ""
print
}
}
exit 0
}
用法:awk -f script.awk filea fileb