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

У меня есть файл, который выглядит так:

20:60479_C_T 60479 C T  0 0 0 0 0 1 0 1
20:60522_T_TC 60522 T TC        0 0 0 0 0 0 0 
20:60568_A_C 60568 A C  0 0 1 0 0 1 
20:60571_C_A 60571 C A  0 1 0 1 0 0 
20:60579_G_A 60579 G A  0 0 1 0 0 0 

Мой текущий файл больше с 3 миллионами строк и 3000 столбцов. Я хочу использовать значения в столбцах $3 и $4 для замены 0 и 1 в остальных столбцах. Желаемый результат будет:

20:60479_C_T 60479 C T  C C C C C T C T
20:60522_T_TC 60522 T TC        T T T T T T T 
20:60568_A_C 60568 A C  A A C A A C 
20:60571_C_A 60571 C A  C A C A C C 
20:60579_G_A 60579 G A  G G A G G G 

Я знаю, как это сделать для пары столбцов:

awk '{d["0"]=$3; d["1"]=$4; print "20", $1, "0", $2, d[$5], d[$6];}' myfile

Но я не знаю, как сделать это автоматически для всех столбцов и избежать добавления всех столбцов вручную

Ответы [ 3 ]

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

Поскольку у вас есть переменное количество столбцов, вы, вероятно, можете получить что-то вроде:

awk <testprog.in '{for (i = 5; i <= NF; i++){$i = $($i+3)}print}'

"Волшебство" здесь - это присвоение от $($i+3) до $i для всех значений i между 5 и количеством полей (включительно).

Выражение $i+3 превратит 0 и 1 в 3 и 4 соответственно, поэтому следующим шагом будет оценка $3 или $4 (C и T например, в первой строке) и использовать его для замены элемента.

Результат вашего маленького теста, как и ожидалось:

20:60479_C_T 60479 C T C C C C C T C T
20:60522_T_TC 60522 T TC T T T T T T T
20:60568_A_C 60568 A C A A C A A C
20:60571_C_A 60571 C A C A C A C C
20:60579_G_A 60579 G A G G A G G G

Вам, конечно, нужно будет проверить производительность этого с вашими большими наборами данных. На моем компьютере файл с тремя миллионами строк и 3000 записей занимает около получаса.

Сравните это с программой на C (хотя она, по общему признанию, quick'n'dirty, сильно привязана к вашим специфическим входным данным, без того, что я обычно считаю необходимой проверкой ошибок), которая занимает всего около десяти минут.

Для полноты, вот вариант C, который, предполагая, что он называется prog.c, вы можете скомпилировать с чем-то вроде gcc -o prog prog.c и запустить с чем-то вроде ./prog <testprog.in:

#include <stdio.h>
#include <ctype.h>

static char buff[102040];

static char *getStr(char *buff, int *pSz) {
    if (*buff == 0) return NULL;

    char *nextBuff = buff;
    while ((nextBuff[0] != 0) && isspace(nextBuff[0])) {
        nextBuff++;
    }
    if (*nextBuff == 0) return NULL;

    *pSz = 0;
    while ((nextBuff[*pSz] != 0) && ! isspace(nextBuff[*pSz])) {
        (*pSz)++;
    }

    return nextBuff;
}

int main(void) {
    char *str, *str3, *str4; int sz, sz3, sz4;

    while (fgets(buff, sizeof(buff), stdin) != NULL) {
        str = getStr(buff, &sz); printf("%*.*s", sz, sz, str);
        str = getStr(str + sz, &sz); printf(" %*.*s", sz, sz, str);
        str3 = getStr(str + sz, &sz3); printf(" %*.*s", sz3, sz3, str3); 
        str4 = getStr(str3 + sz3, &sz4); printf(" %*.*s", sz4, sz4, str4);

        str = getStr(str4 + sz4, &sz);
        while (str != NULL) {
            if (*str == '0') {
                printf(" %*.*s", sz3, sz3, str3);
            } else {
                printf(" %*.*s", sz4, sz4, str4);
            }
            str = getStr(str + sz, &sz);
        }
        printf("\n");
    }
    return 0;
}
0 голосов
/ 17 сентября 2018
$ awk '{d[0]=$3; d[1]=$4; for (i=5; i<=NF; i++) $i=d[$i]} 1' file
20:60479_C_T 60479 C T C C C C C T C T
20:60522_T_TC 60522 T TC T T T T T T T
20:60568_A_C 60568 A C A A C A A C
20:60571_C_A 60571 C A C A C A C C
20:60579_G_A 60579 G A G G A G G G
0 голосов
/ 17 сентября 2018

Используя gsub в awk, вы можете попробовать это как вариант:

$ awk '{d[1]=$1;d[2]=$2;gsub(/0/,$3);gsub(/1/,$4);$1=d[1];$2=d[2];}1' myfile
20:60479_C_T 60479 C T C C C C C T C T
20:60522_T_TC 60522 T TC T T T T T T T
20:60568_A_C 60568 A C A A C A A C
20:60571_C_A 60571 C A C A C A C C
20:60579_G_A 60579 G A G G A G G G
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...