Самый быстрый способ сортировки текстового файла по образцу идентификаторов

Мне нужно отсортировать файл mwe.txt:

>gb|LOEQ01000001.1|
1   CC|1    CC|1    NN|0    NN|0    NN|0    CC|1    NN|0    CC|1    CC|1    CC|1
2   AA|1    AA|1    NN|0    NN|0    NN|0    AA|1    NN|0    AA|1    AA|1    AA|1
>gb|LOEQ01000181.1|
1   CC|1    CC|1    NN|0    NN|0    NN|0    CC|1    NN|0    CC|1    CC|1    CC|1
>gb|LOEQ01000131.1|
1   CC|1    CC|1    NN|0    NN|0    NN|0    CC|1    NN|0    CC|1    CC|1    CC|1
2   AA|1    AA|1    NN|0    NN|0    NN|0    AA|1    NN|0    AA|1    AA|1    AA|1
3   AA|1    AA|1    NN|0    NN|0    NN|0    AA|1    NN|0    AA|1    AA|1    AA|1

по образцу идентификаторов в names.txt:

LOEQ01000001.1
LOEQ01000131.1
LOEQ01000181.1

Я смог добиться этого с помощью sed и awk:

for f in $(cat names.txt); do sed -n -e "/$f|/,/>/ p" mwe.txt | awk '/>/&&c++>0 {next} 1' >> sorted.txt; done

Что приводит к:

>gb|LOEQ01000001.1|
1   CC|1    CC|1    NN|0    NN|0    NN|0    CC|1    NN|0    CC|1    CC|1    CC|1
2   AA|1    AA|1    NN|0    NN|0    NN|0    AA|1    NN|0    AA|1    AA|1    AA|1
>gb|LOEQ01000131.1|
1   CC|1    CC|1    NN|0    NN|0    NN|0    CC|1    NN|0    CC|1    CC|1    CC|1
2   AA|1    AA|1    NN|0    NN|0    NN|0    AA|1    NN|0    AA|1    AA|1    AA|1
3   AA|1    AA|1    NN|0    NN|0    NN|0    AA|1    NN|0    AA|1    AA|1    AA|1
>gb|LOEQ01000181.1|
1   CC|1    CC|1    NN|0    NN|0    NN|0    CC|1    NN|0    CC|1    CC|1    CC|1

Фактические файлы, которые я использую, имеют размер>120 ГБ, и мое решение действительно неэффективно. Я предполагаю, что возможно использовать алгоритм рекурсивной сортировки слиянием, но я не уверен, как организовать входные данные, чтобы их можно было сортировать, в основном из-за несовместимого количества строк для каждого образца / идентификатора. Кто-нибудь может предложить более быстрый путь?

1 ответ

$ cat tst.awk
BEGIN { FS="|" }
NR==FNR { keys[++numKeys] = $0; next }
/^>/ { key = $2 }
{ block[key] = block[key] $0 ORS }
END {
    for (keyNr=1; keyNr<=numKeys; keyNr++) {
        key = keys[keyNr]
        printf "%s", block[key]
    }
}

$ awk -f tst.awk names.txt mwe.txt
>gb|LOEQ01000001.1|
1   CC|1    CC|1    NN|0    NN|0    NN|0    CC|1    NN|0    CC|1    CC|1    CC|1
2   AA|1    AA|1    NN|0    NN|0    NN|0    AA|1    NN|0    AA|1    AA|1    AA|1
>gb|LOEQ01000131.1|
1   CC|1    CC|1    NN|0    NN|0    NN|0    CC|1    NN|0    CC|1    CC|1    CC|1
2   AA|1    AA|1    NN|0    NN|0    NN|0    AA|1    NN|0    AA|1    AA|1    AA|1
3   AA|1    AA|1    NN|0    NN|0    NN|0    AA|1    NN|0    AA|1    AA|1    AA|1
>gb|LOEQ01000181.1|
1   CC|1    CC|1    NN|0    NN|0    NN|0    CC|1    NN|0    CC|1    CC|1    CC|1

Это будет быстрее, но это означает, что вам нужно сохранить весь файл в памяти, так что попробуйте и посмотрите, если это проблема. Если это так, вы можете взять подмножество имен ключей одновременно и использовать что-то вроде этого сценария:

$ cat tst.awk
BEGIN { FS="|" }
NR==FNR { keys[++numKeys] = $0; tgtKeys[$0]; next }
/^>/ { key = $2 }
key in tgtKeys { block[key] = block[key] $0 ORS }
END {
    for (keyNr=1; keyNr<=numKeys; keyNr++) {
        key = keys[keyNr]
        printf "%s", block[key]
    }
}

< names.txt xargs -n 1000 echo | awk -f tst.awk - mwe.txt

который будет печатать строку из mwe.txt 1000 за один раз.

Другие вопросы по тегам