一部のコードを Python から C++ に移動します。
BASEPAIRS = { "T": "A", "A": "T", "G": "C", "C": "G" }
地図を考えることはやり過ぎかもしれませんか? 何を使いますか?
一部のコードを Python から C++ に移動します。
BASEPAIRS = { "T": "A", "A": "T", "G": "C", "C": "G" }
地図を考えることはやり過ぎかもしれませんか? 何を使いますか?
次の構文を使用できます。
#include <map>
std::map<char, char> my_map = {
{ 'A', '1' },
{ 'B', '2' },
{ 'C', '3' }
};
最適化に関心があり、入力が常に 4 文字のいずれかであると想定している場合は、マップの代わりに以下の関数を試してみる価値があるかもしれません。
char map(const char in)
{ return ((in & 2) ? '\x8a' - in : '\x95' - in); }
これは、2 つの対称ペアを扱っているという事実に基づいて機能します。条件は、A/T ペアと G/C ペアを区別するように機能します (「G」と「C」はたまたま 2 番目の最下位ビットを共有しています)。残りの演算は、対称マッピングを実行します。これは、a = (a + b) - b が任意の a,b に対して真であるという事実に基づいています。
を使用してstd::map
も問題ないか、256 サイズの char テーブルを使用しても問題ありませんが、単にenum
. C++11 機能がある場合はenum class
、強力な型付けに使用できます。
// 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
};
使い方は簡単です:
int main (int argc, char* argv[] ) {
BasePair bp = BasePair::A;
BasePair complimentbp = Complimentary[(int)bp];
}
これが多すぎる場合は、ヘルパーを定義して人間が読める ASCII 文字を取得し、塩基対の補数を取得して、(int)
常にキャストを行わないようにすることができます。
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 ];
}
クリーンで、シンプルで、効率的です。
ここで突然、256 バイトのテーブルがなくなりました。また、文字 (それぞれ 1 バイト) を格納していないため、これをファイルに書き込む場合は、塩基対ごとに 1 バイト (8 ビット) ではなく、塩基対ごとに 2 ビットを書き込むことができます。データをそれぞれ1文字として保存するバイオインフォマティクスファイルを使用する必要がありました。利点は、人間が判読できることです。短所は、250 MB のファイルであるべきものが 1 GB の容量を消費してしまうことです。移動と保管と使用は悪夢でした。もちろん、250 MB は、ワームの DNA を含めても余裕があります。いずれにしても、1 GB 相当の塩基対を読み取る人間はいません。
パフォーマンスを本当に気にするまでは、ベースを取り、その一致を返す関数を使用していました。
char base_pair(char base)
{
switch(base) {
case 'T': return 'A';
... etc
default: // handle error
}
}
パフォーマンスが気になる場合は、ベースを 4 分の 1 バイトと定義します。0 は A、1 は G、2 は C、3 は T を表します。次に、4 つの塩基を 1 バイトにパックし、それらのペアを取得するには、単純に補数を取ります。
マップソリューションは次のとおりです。
#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;
}
char 配列からのテーブル:
char map[256] = { 0 };
map['T'] = 'A';
map['A'] = 'T';
map['C'] = 'G';
map['G'] = 'C';
/* .... */
これは、私が考えることができる最も速く、最も単純で、最小の宇宙ソリューションです。優れた最適化コンパイラは、ペア配列と名前配列にアクセスするコストを削減します。このソリューションは、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 []は、Baseへの高速ASCII文字(つまり、0から3までのint)ルックアップであり、少し醜いです。優れた最適化コンパイラはbase2()を処理できるはずですが、処理できるかどうかはわかりません。
BASEPAIRS = { "T": "A", "A": "T", "G": "C", "C": "G" } 何を使いますか?
多分:
static const char basepairs[] = "ATAGCG";
// lookup:
if (const char* p = strchr(basepairs, c))
// use p[1]
;-)