Как отсортировать мой список наиболее частых 3-мер в порядке возрастания?

#c #c #bioinformatics

#c #c #биоинформатика

Вопрос:

Я пишу код, чтобы найти наиболее частые 3-мер в последовательности ДНК. Я написал код, который подсчитывает вхождение 3-мер, и если оно больше 1, то код записывает как строку, так и количество вхождений.

Это дает мне список, который является избыточным по своей природе. Я хочу отсортировать список так, чтобы я видел каждый 3-мер только один раз в списке.

Ниже приведен код, который написал:

 int main()
{
    char dna[1000];
    char read[3] = {0};
    char most_freq[3];

    printf("Enter the DNA sequencen");
    fgets(dna, sizeof(dna), stdin);
    int i, j;
    for(i=0; i<strlen(dna)-3; i  )
    {

        read[0] = dna[i];
        read[1] = dna[i 1];
        read[2] = dna[i 2];
        int count=0, maxcount=1;
        for(j = 0; j < strlen(dna); j  )
        {
            if(dna[j] == read[0] amp;amp; dna[j 1] == read[1] amp;amp; dna[j 2] == read[2])
            {
                count  ;
            }
            else
            {
                continue;
            }
        }
        if(count > maxcount)
        {
            maxcount = count;
            
           printf("%s %dn", read, maxcount);
        }

    }
}
  

Это то, что я получаю, если я ввожу :

CGCCTAAATAGCCTCGCGGAGCCTTATGTCATACTCGTCCT

 CGC 2
GCC 3
CCT 4
ATA 2
AGC 2
GCC 3
CCT 4
CTC 2
TCG 2
CGC 2
AGC 2
GCC 3
CCT 4
GTC 2
ATA 2
CTC 2
TCG 2
GTC 2
CCT 4
  

Понятно, что ответ — CCT, но я не хочу избыточности в выводе. Как мне решить эту проблему?

Комментарии:

1. Вы могли бы использовать набор (точнее, несколько наборов ) для сохранения результата. Или какая-то карта , которая сопоставляет 3-мер с количеством. Или просто динамический массив структур, содержащий 3-мер и количество, которые затем можно сортировать, удалять дубликаты и отображать.

2. @Someprogrammerdude Проблема была помечена как C нет C

3. @AlexShirley Я не упомянул никаких конкретных реализаций (кроме динамического массива структур), только общие структуры данных, которые доступны или могут быть реализованы на любом языке.

4. Может быть, медуза (быстрый подсчет k-мер) ссылка

5. Я пытаюсь написать свой собственный код для решения проблемы. Но, jellyfish — это вариант, если все работает не так, как я хочу.

Ответ №1:

Вот достаточно быстрый способ сделать это в C

 #include <stdlib.h>
#include <string.h>
#include <stdio.h>

typedef struct {
    char n_base[4];
    int count;
} NMer_3;

typedef struct {
    int count;
    NMer_3 trimer[4 * 4 * 4];
} dict;

int cmp(const void* a, const void* b) {
    return strncmp((char*)a, (char*)b, 3);
}

void insertTrimer(dict* d, char c[3]) {
    NMer_3* ptr = (NMer_3*)bsearch((void*)c, (void*)d->trimer, d->count,
                                   sizeof(NMer_3), cmp);
    if (ptr == NULL) {
        int offset = d->count;
        strncpy(d->trimer[offset].n_base, c, 3);
        d->trimer[offset].count = 1;
        d->count  ;
        qsort(d->trimer, d->count, sizeof(NMer_3), cmp);
    } else {
        ptr->count  ;
    }
}

int main() {
    char dna[1000];
    dict d;
    printf("Enter the DNA sequencen");
    char* res = fgets(dna, sizeof(dna), stdin);
    if (res == NULL)
        return 1;
    char* ptr = amp;dna[0];
    for (int i = 0; i < strlen(dna) - 2; i  )
        insertTrimer(amp;d, ptr  );
    for (int i = 0; i < d.count; i  )
        printf("%s : %dn", d.trimer[i].n_base, d.trimer[i].count);
    return 0;
}
  

По сути, каждый 3-мер является записью в более крупной структуре. Большая структура выполняется с двоичным поиском и q-сортируется каждый раз, когда обнаруживается новый 3-мер. В противном случае, если найдено повторение, их запись увеличивается.

Вот результат, используемый с вашим вводом

 AAA : 1
AAT : 1
ACT : 1
AGC : 2
ATA : 2
ATG : 1
CAT : 1
CCT : 4
CGC : 2
CGG : 1
CGT : 1
CTA : 1
CTC : 2
CTT : 1
GAG : 1
GCC : 3
GCG : 1
GGA : 1
GTC : 2
TAA : 1
TAC : 1
TAG : 1
TAT : 1
TCA : 1
TCC : 1
TCG : 2
TGT : 1
TTA : 1
  

Способы повышения скорости:

  • Используйте программу, подобную Jellyfish
  • Используйте hashmap. Для хэш-карт / таблиц нет стандартной C-библиотеки. Вы в основном собираетесь сделать что-то очень похожее на то, что я сделал здесь. Управление памятью может быть проблемой. Однако вы собираетесь выполнять поиск O (1) для каждого 3-мер в последовательности вместо O (log (n)), кроме того, добавление будет только O (1) вместо необходимости сортировки O (n * log (n)) .

Если вы делаете это на C , вы получаете много преимуществ, первое из которых — гораздо более простой код:

 #include <string>
#include <iostream>
#include <map>

int main() {
    std::string dna;
    printf("Enter the DNA sequencen");
    std::getline(std::cin, dna);
    auto d = std::map<std::string,int>{};
    for (int i = 0; i < dna.size() - 2; i  ){
        auto mer3 = dna.substr(i,3);
        auto itr = d.find(mer3);
        if (itr == d.end()){
            d[mer3] = 1;
        } else {
            itr->second  = 1;
        }
    }
    for (auto i : d) std::cout << i.first << ':' << i.second << 'n';
    std::cout <<std::endl;
    return 0;
}
  

Это фактически то же самое, что и в примере C.

map Однако, если вы замените unordered_map его, он станет намного быстрее, вывод не будет отсортирован.