Déplacement du code de Python vers C++.
BASEPAIRS = { "T": "A", "A": "T", "G": "C", "C": "G" }
Cartes de réflexion pourrait être exagéré? Qu'utiliseriez-vous?
Si vous êtes dans l'optimisation, et en supposant que l'entrée soit toujours l'un des quatre caractères, la fonction ci-dessous peut valoir un essai pour remplacer la carte:
char map(const char in)
{ return ((in & 2) ? '\x8a' - in : '\x95' - in); }
Cela fonctionne sur la base du fait que vous avez affaire à deux paires symétriques. Le conditionnel permet de distinguer le couple A/T du groupe G/C (il arrive que "G" et "C" aient en commun le deuxième bit le moins significatif). L'arithmétique restante effectue la cartographie symétrique. Elle est basée sur le fait que a = (a + b) - b est vrai pour tout a, b.
Vous pouvez utiliser la syntaxe suivante:
std::map<char, char> my_map = {
{ 'A', '1' },
{ 'B', '2' },
{ 'C', '3' }
};
En utilisant un std::map
est bien ou utiliser une table de caractères de 256 tailles serait une bonne chose, vous pourriez économiser une énorme quantité d’agonie en utilisant simplement un enum
. Si vous avez des fonctionnalités C++ 11, vous pouvez utiliser enum class
pour le typage fort:
// 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
};
L'utilisation devient simple:
int main (int argc, char* argv[] ) {
BasePair bp = BasePair::A;
BasePair complimentbp = Complimentary[(int)bp];
}
Si c'est trop pour vous, vous pouvez définir des aides pour obtenir des caractères lisibles par l'homme ASCII) et pour obtenir le complément de la paire de base afin que vous ne fassiez pas (int)
lance tout le temps:
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 ];
}
C'est propre, c'est simple et efficace.
Maintenant, tout à coup, vous n'avez pas une table de 256 octets. Vous ne stockez pas non plus de caractères (1 octet chacun). Ainsi, si vous écrivez ceci dans un fichier, vous pouvez écrire 2 bits par paire de base au lieu de 1 octet (8 bits) par paire de base. Je devais travailler avec des fichiers bioinformatiques qui stockaient les données sous la forme d'un caractère chacune. L'avantage est que c'était lisible par l'homme. Le problème, c'est que ce qui aurait dû être un fichier de 250 Mo a pris 1 Go d'espace. Mouvement et stockage et utilisation était un cauchemar. Bien sûr, 250 Mo représentent généreux en tenant compte même de l’ADN du ver. De toute façon, aucun humain ne lira au moins 1 Go de paires de bases.
Jusqu'à ce que je sois vraiment préoccupé par les performances, j'utilisais une fonction qui prend une base et retourne sa correspondance:
char base_pair(char base)
{
switch(base) {
case 'T': return 'A';
... etc
default: // handle error
}
}
Si la performance m'inquiétait, je définirais une base comme un quart d'octet. 0 représenterait A, 1 représenterait G, 2 représenterait C et 3 représenterait T. Ensuite, je mettrais 4 bases dans un octet, et pour obtenir leurs paires, je prendrais simplement le complément.
Une table hors tableau de caractères:
char map[256] = { 0 };
map['T'] = 'A';
map['A'] = 'T';
map['C'] = 'G';
map['G'] = 'C';
/* .... */
Voici la solution cartographique:
#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;
}
C’est la solution la plus rapide, la plus simple et la plus compacte à laquelle je puisse penser. Un compilateur d'optimisation efficace supprimera même le coût d'accès à la paire et aux tableaux de noms. Cette solution fonctionne aussi bien en 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 [] est un caractère ascii rapide à la base (c'est-à-dire un entier compris entre 0 et 3 inclus) qui est un peu moche. Un bon compilateur optimiseur devrait être capable de gérer base2 (), mais je ne suis pas sûr que ce soit le cas.
BASEPAIRS = {"T": "A", "A": "T", "G": "C", "C": "G"} Que utiliseriez-vous?
Peut être:
static const char basepairs[] = "ATAGCG";
// lookup:
if (const char* p = strchr(basepairs, c))
// use p[1]
;-)