Перемещение кода с Python на C++.Простой словарь в C++
BASEPAIRS = { "T": "A", "A": "T", "G": "C", "C": "G" }
Мыслительные карты могут быть излишними? Что бы вы использовали?
Перемещение кода с Python на C++.Простой словарь в C++
BASEPAIRS = { "T": "A", "A": "T", "G": "C", "C": "G" }
Мыслительные карты могут быть излишними? Что бы вы использовали?
Если вы в оптимизации, и предполагая, что вход всегда один из четырех символов, функция ниже может быть стоит попробовать в качестве замены карты :
char map(const char in)
{ return ((in & 2) ? '\x8a' - in : '\x95' - in); }
Это работает на основе того факта, что вы имеете дело с двумя симметричными парами. Условные работы, чтобы отличить пару A/T от G/C, один («G» и «C» имеют второй по значению младший бит). Оставшаяся арифметика выполняет симметричное отображение. Это основано на том, что a = (a + b) - b истинно для любых a, b.
Стол из массива полукокса:
char map[256] = { 0 };
map['T'] = 'A';
map['A'] = 'T';
map['C'] = 'G';
map['G'] = 'C';
/* .... */
Пока я не был действительно обеспокоен производительности, я хотел бы использовать функцию, которая принимает базу и возвращает его матч:
char base_pair(char base)
{
switch(base) {
case 'T': return 'A';
... etc
default: // handle error
}
}
Если я был обеспокоен производительностью, я бы определил базу как одну четверть байта. 0 будет представлять A, 1 будет представлять G, 2 будет представлять C, а 3 будет представлять T. Тогда я бы упаковал 4 байт в байт и, чтобы получить их пары, я бы просто взял дополнение.
Вот карта решение:
#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;
}
Несвязанный, но вы переполняете поток. – Rapptz
пар оснований = { "Т": "А", "А": "Т", "G": "С", "С": " G "} Что бы вы использовали?
Может быть:
static const char basepairs[] = "ATAGCG";
// lookup:
if (const char* p = strchr(basepairs, c))
// use p[1]
;-)
Во время использования std::map
является штраф или с использованием 256-размера таблицы символ будет хорошо, вы могли бы сэкономить огромное количество космической агонии просто используя 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 ];
}
это чистое, это просто, и его efficie нт.
Теперь, у вас нет 256-байтового стола. Вы также не храните символы (по 1 байт каждый), и, таким образом, если вы пишете это в файл, вы можете записать 2 бита на базовую пару вместо 1 байта (8 бит) на базовую пару. Мне пришлось работать с файлами Bioinformatics, которые сохраняли данные по 1 символу. Преимущество в том, что оно было доступно для человека. Кон - то, что должно было быть 250 МБ-файлом, в итоге заняло 1 ГБ места. Движение, хранение и использование были кошмаром. Из coursse, 250 MB является щедрым при учете даже ДНК червя. В любом случае ни один человек не будет читать парные пары на 1 ГБ.
Но это все еще нуждается в линейном времени поиска для преобразования базовой пары в базовую пару. – perreal
@perreal. Если «Линейное время поиска» означает «O (1)», то да, это все помещение O (1), а также максимально сжато для очень немного усилия. – 2013-03-01 06:33:24
@perreal Не могли бы вы объяснить, как это линейное время? Поистине интересно. – Rapptz
Вы можете использовать следующий синтаксис:
std::map<char, char> my_map = {
{ 'A', '1' },
{ 'B', '2' },
{ 'C', '3' }
};
Только в C++ 11. – congusbongus
Это самое быстрое, самое простое, самое маленькое космическое решение, о котором я могу думать. Хороший оптимизирующий компилятор даже удалит стоимость доступа к массивам пар и имен. Это решение работает одинаково хорошо в С.
#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;
}
};
баз [] является быстрым ASCII-символ на базу (т.е. INT в диапазоне от 0 до 3 включительно) поиска, который является немного некрасиво. Хороший оптимизирующий компилятор должен иметь возможность обрабатывать base2(), но я не уверен, что делать.
Но это решение предполагает, что ввод поступает как числа 0, 1, 2, 3, а не символы ASCII. Вам все равно придется выполнить сопоставление ввода, правильно? – jogojapan
Хорошая точка. Я исправил его с самым быстрым отображением, о котором я мог думать, и более красивым, но, возможно, более медленным отображением на основе коммутаторов. –
Почему карта может быть излишней? – ForEveR
Что вы планируете делать с ними? – bchurchill
Могу ли я определить карту как константу с базовыми значениями как-то в определении класса? – y2k