awk: искать дублированные поля в нескольких столбцах, печатать новый столбец при условии - PullRequest
0 голосов
/ 11 сентября 2018

Мне нужна ваша помощь с awk.Я пытаюсь найти строки, в которых столбцы $1 и $2 дублированы в файле и где хотя бы один из дубликатов имеет значение ref в столбце $3.Если это так, выведите "1" else print "2" в новом столбце.

Примером входного файла будет:

a       123     exp_a
a       123     ref
b       146     exp_a
c       156     ref
d       205     exp_a
d       205     exp_b

, а выходным файлом будет:

a       123     exp_a     1
a       123     ref       1
b       146     exp_a     2
c       156     ref       2
d       205     exp_a     2
d       205     exp_b     2

Здесь a 123 дублируется одной строкой, имеющей ref в $3, поэтому он получает 1.Напротив, остальные либо не дублируются в $1 и $2, либо дублируются, но без ref в $3, поэтому они получают 2.

После некоторого возни, яудается поместить 1 в строки, где дублируются $1 и $2, но это не учитывает ref в $3, и я не могу сказать awk для печати 2 в противном случае ... СПОЙЛЕРЫ: мой код, вероятно, очень уродлив.

awk 'BEGIN {FS=OFS="\t"} {i=$1FS$2} {a[i]=!a[i]?$3:a[i]FS"1\n" i"\t"$3FS"1"} END {for (l in a) {print l,a[l]}}' infile > outfile

Вывод, который я получаю:

d       205     exp_a   1
d       205     exp_b   1
a       123     exp_a   1
a       123     ref     1
b       146     exp_a
c       156     ref

Ответы [ 3 ]

0 голосов
/ 11 сентября 2018

Этот работает за один раз данных, но ожидает, что файл будет упорядочен по $1 $2, «ключу». Записи в каждой «ключевой» группе выводятся в случайном порядке (for(i in a)):

awk '
BEGIN { FS=OFS="\t" }
{
    if((p!=$1 OFS $2) && NR>1) {            # when the $1 $2 changes from previous
        for(i=1;i<=a[0];i++) {              # iterate and output buffered records
            print p,a[i],2-(a[-1]&&a[0]>1)  # more than one record in buffer and ...
        }                                   # ... ref for $4=1
        delete a                            # empty buffer after output
    }
    if($3=="ref")                           # if there is a match in $3
        a[-1]++                             # increase counter
    a[++a[0]]=$3                            # buffer records to a, a[0] counter
    p=$1 OFS $2                             # p is for previous "key"
}
END {
    for(i=1;i<=a[0];i++)                    # duplicate code from above if
        print p,a[i],2-(a[-1]&&a[0]>1)
}' file

Выходы:

a       123     exp_a   1
a       123     ref     1
b       146     exp_a   2
c       156     ref     2
d       205     exp_a   2
d       205     exp_b   2

Счетчик записей a[0] и счетчик ссылок a[-1] находятся в a[], чтобы сбросить их с помощью одного delete a.

0 голосов
/ 11 сентября 2018
$ cat tst.awk
BEGIN { OFS="\t" }
NR==FNR {
    cnt2[$1,$2]++
    cnt3[$1,$2,$3]++
    next
}
{ print $0, (cnt2[$1,$2]>1 && cnt3[$1,$2,"ref"]>0 ? 1 : 2) }

$ awk -f tst.awk file file
a       123     exp_a   1
a       123     ref     1
b       146     exp_a   2
c       156     ref     2
d       205     exp_a   2
d       205     exp_b   2
0 голосов
/ 11 сентября 2018

Не могли бы вы попробовать следующее.

awk 'FNR==NR{a[$1,$2]++;b[$1,$2]=$3;next} {$NF=(b[$1,$2]=="ref" && a[$1,$2]>1?$NF OFS "1":$NF OFS "2")} 1' OFS="\t"  Input_file  Input_file

Здесь также добавлена ​​не-линейная форма решения.

awk '
FNR==NR{
  a[$1,$2]++
  b[$1,$2]=$3
  next
}
{
  $NF=(b[$1,$2]=="ref" && a[$1,$2]>1?$NF OFS "1":$NF OFS "2")
}
1
' OFS="\t" Input_file Input_file
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...