Eenvoudig woordenboek in C++

Een stukje code verplaatsen van Python naar C++.

BASEPAIRS = { "T": "A", "A": "T", "G": "C", "C": "G" }

Denken dat kaarten misschien overdreven zijn? Wat zou je gebruiken?


Antwoord 1, autoriteit 100%

Als je van optimalisatie houdt en ervan uitgaat dat de invoer altijd een van de vier tekens is, kan de onderstaande functie het proberen waard zijn als vervanging voor de kaart:

char map(const char in)
{ return ((in & 2) ? '\x8a' - in : '\x95' - in); }

Het werkt op basis van het feit dat je te maken hebt met twee symmetrische paren. De voorwaardelijke werkt om het A/T-paar te onderscheiden van het G/C-paar (‘G’ en ‘C’ hebben toevallig het op één na minst significante bit gemeen). De resterende rekenkunde voert de symmetrische afbeelding uit. Het is gebaseerd op het feit dat a = (a + b) – b waar is voor elke a,b.


Antwoord 2, autoriteit 90%

U kunt de volgende syntaxis gebruiken:

#include <map>
std::map<char, char> my_map = {
    { 'A', '1' },
    { 'B', '2' },
    { 'C', '3' }
};

Antwoord 3, autoriteit 81%

Hoewel het gebruik van een std::map prima is of het gebruik van een char-tabel van 256 formaat prima zou zijn, zou je jezelf een enorme hoeveelheid ruimtepijn kunnen besparen door simpelweg een enum. Als je C++11-functies hebt, kun je enum class gebruiken voor sterk typen:

// First, we define base-pairs. Because regular enums
// Pollute the global namespace, I'm using "enum class". 
enum class BasePair {
    A,
    T,
    C,
    G
};
// Let's cut out the nonsense and make this easy:
// A is 0, T is 1, C is 2, G is 3.
// These are indices into our table
// Now, everything can be so much easier
BasePair Complimentary[4] = {
    T, // Compliment of A
    A, // Compliment of T
    G, // Compliment of C
    C, // Compliment of G
};

Gebruik wordt eenvoudig:

int main (int argc, char* argv[] ) {
    BasePair bp = BasePair::A;
    BasePair complimentbp = Complimentary[(int)bp];
}

Als dit teveel voor je is, kun je een aantal helpers definiëren om voor mensen leesbare ASCII-tekens te krijgen en ook om het basenpaar-compliment te krijgen, zodat je niet alle (int)-casts doet tijd:

BasePair Compliment ( BasePair bp ) {
    return Complimentary[(int)bp]; // Move the pain here
}
// Define a conversion table somewhere in your program
char BasePairToChar[4] = { 'A', 'T', 'C', 'G' };
char ToCharacter ( BasePair bp ) {
    return BasePairToChar[ (int)bp ];
}

Het is schoon, eenvoudig en efficiënt.

Nu heb je opeens geen tabel van 256 bytes. Je slaat ook geen karakters op (elk 1 byte), en dus als je dit naar een bestand schrijft, kun je 2 bits per basenpaar schrijven in plaats van 1 byte (8 bits) per basenpaar. Ik moest werken met Bioinformatics Files die gegevens elk met 1 teken opsloegen. Het voordeel is dat het leesbaar was voor mensen. Het nadeel is dat wat een bestand van 250 MB had moeten zijn, uiteindelijk 1 GB aan ruimte in beslag nam. Beweging en opslag en gebruik was een nachtmerrie. Natuurlijk, 250 MB is royaal als we zelfs Worm-DNA meerekenen. Geen mens zal hoe dan ook 1 GB aan basenparen lezen.


Antwoord 4, autoriteit 38%

Totdat ik me echt zorgen maakte over de prestaties, zou ik een functie gebruiken die een basis neemt en de overeenkomst teruggeeft:

char base_pair(char base)
{
    switch(base) {
        case 'T': return 'A';
        ... etc
        default: // handle error
    }
}

Als ik me zorgen zou maken over de prestaties, zou ik een basis definiëren als een vierde van een byte. 0 zou A voorstellen, 1 zou G voorstellen, 2 zou C vertegenwoordigen, en 3 zou T vertegenwoordigen. Dan zou ik 4 basen in een byte inpakken, en om hun paren te krijgen, zou ik gewoon het complement nemen.


Antwoord 5, autoriteit 31%

Een tabel uit char array:

char map[256] = { 0 };
map['T'] = 'A'; 
map['A'] = 'T';
map['C'] = 'G';
map['G'] = 'C';
/* .... */

Antwoord 6, autoriteit 31%

Dit is de kaartoplossing:

#include <iostream>
#include <map>
typedef std::map<char, char> BasePairMap;
int main()
{
    BasePairMap m;
    m['A'] = 'T';
    m['T'] = 'A';
    m['C'] = 'G';
    m['G'] = 'C';
    std::cout << "A:" << m['A'] << std::endl;
    std::cout << "T:" << m['T'] << std::endl;
    std::cout << "C:" << m['C'] << std::endl;
    std::cout << "G:" << m['G'] << std::endl;
    return 0;
}

Antwoord 7, autoriteit 8%

Dit is de snelste, eenvoudigste en kleinste ruimteoplossing die ik kan bedenken. Een goede optimaliserende compiler zal zelfs de kosten voor toegang tot de paar- en naamarrays wegnemen. Deze oplossing werkt even goed in C.

#include <iostream>
enum Base_enum { A, C, T, G };
typedef enum Base_enum Base;
static const Base pair[4] = { T, G, A, C };
static const char name[4] = { 'A', 'C', 'T', 'G' };
static const Base base[85] = 
  { -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 
    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
    -1, -1, -1, -1, -1,  A, -1,  C, -1, -1,
    -1,  G, -1, -1, -1, -1, -1, -1, -1, -1, 
    -1, -1, -1, -1,  T };
const Base
base2 (const char b)
{
  switch (b)
    {
    case 'A': return A;
    case 'C': return C;
    case 'T': return T;
    case 'G': return G;
    default: abort ();
    }
}
int
main (int argc, char *args) 
{
  for (Base b = A; b <= G; b++)
    {
      std::cout << name[b] << ":" 
                << name[pair[b]] << std::endl;
    }
  for (Base b = A; b <= G; b++)
    {
      std::cout << name[base[name[b]]] << ":" 
                << name[pair[base[name[b]]]] << std::endl;
    }
  for (Base b = A; b <= G; b++)
    {
      std::cout << name[base2(name[b])] << ":" 
                << name[pair[base2(name[b])]] << std::endl;
    }
};

base[] is een snelle ascii-char naar Base (d.w.z. int tussen 0 en 3 inclusief) lookup die een beetje lelijk is. Een goede optimaliserende compiler zou base2() moeten kunnen verwerken, maar ik weet niet zeker of dat wel het geval is.


Antwoord 8, autoriteit 4%

BASEPAAIRS = { “T”: “A”, “A”: “T”, “G”: “C”, “C”: “G” }
Wat zou je gebruiken?

Misschien:

static const char basepairs[] = "ATAGCG";
// lookup:
if (const char* p = strchr(basepairs, c))
    // use p[1]

😉

LEAVE A REPLY

Please enter your comment!
Please enter your name here

18 + six =

Other episodes