64

将一些代码从 Python 移动到 C++。

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

思维导图可能是矫枉过正?你会用什么?

4

8 回答 8

119

您可以使用以下语法:

#include <map>

std::map<char, char> my_map = {
    { 'A', '1' },
    { 'B', '2' },
    { 'C', '3' }
};
于 2013-03-01T06:28:11.740 回答
28

如果您正在优化,并且假设输入始终是四个字符之一,那么下面的函数可能值得一试作为地图的替代品:

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

它的工作原理是您正在处理两个对称对。条件用于区分 A/T 对和 G/C 对('G' 和 'C' 恰好有第二个最不重要的共同位)。其余算法执行对称映射。它基于以下事实:a = (a + b) - b 对于任何 a,b 都是正确的。

于 2013-03-01T06:32:45.913 回答
23

虽然使用 astd::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 个字节),因此如果您将其写入文件,您可以为每个碱基对写入 2 位,而不是每个碱基对写入 1 个字节(8 位)。我必须使用将数据存储为每个 1 个字符的生物信息学文件。好处是它是人类可读的。缺点是本来应该是 250 MB 的文件最终占用了 1 GB 的空间。移动、存储和使用是一场噩梦。当然,即使考虑到蠕虫 DNA ,250 MB 也是慷慨的。无论如何,没有人会阅读 1 GB 的碱基对。

于 2013-03-01T06:25:46.533 回答
11

在我真正关心性能之前,我会使用一个函数,它接受一个基数并返回它的匹配项:

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

如果我关心性能,我会将基数定义为四分之一字节。0 代表 A,1 代表 G,2 代表 C,3 代表 T。然后我将 4 个碱基打包成一个字节,为了得到它们的对,我只需取补码即可。

于 2013-03-01T06:01:09.570 回答
11

这是地图解决方案:

#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;
}
于 2013-03-01T06:02:57.773 回答
8

char数组中的表:

char map[256] = { 0 };
map['T'] = 'A'; 
map['A'] = 'T';
map['C'] = 'G';
map['G'] = 'C';
/* .... */
于 2013-03-01T05:58:59.843 回答
2

这是我能想到的最快、最简单、最小的空间解决方案。一个好的优化编译器甚至会消除访问 pair 和 name 数组的成本。该解决方案在 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[] 是一个快速的 ascii char 到 Base(即 int 介于 0 和 3 之间)查找,有点难看。一个好的优化编译器应该能够处理 base2() 但我不确定是否有。

于 2013-03-01T06:48:05.010 回答
1

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]

;-)

于 2013-03-01T06:05:10.117 回答