2013-03-01 4 views
23

Перемещение кода с Python на C++.Простой словарь в C++

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

Мыслительные карты могут быть излишними? Что бы вы использовали?

+8

Почему карта может быть излишней? – ForEveR

+0

Что вы планируете делать с ними? – bchurchill

+0

Могу ли я определить карту как константу с базовыми значениями как-то в определении класса? – y2k

ответ

13

Если вы в оптимизации, и предполагая, что вход всегда один из четырех символов, функция ниже может быть стоит попробовать в качестве замены карты :

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

Это работает на основе того факта, что вы имеете дело с двумя симметричными парами. Условные работы, чтобы отличить пару A/T от G/C, один («G» и «C» имеют второй по значению младший бит). Оставшаяся арифметика выполняет симметричное отображение. Это основано на том, что a = (a + b) - b истинно для любых a, b.

+0

Действительно хорошее мышление. – y2k

+0

@WHOEVENCARES Я не уверен, будет ли это быстрее, чем предлагаемый чистый Бенджамин Линдли. Однако, по крайней мере, часть вычитания моей функции может выполняться в векторном регистре для нескольких символов параллельно. – jogojapan

7

Стол из массива полукокса:

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

Не равный питону в любом случае ... Но все зависит от использования ... – ForEveR

+1

Это очень странная карта. – Rapptz

+0

Это невероятно расточительная карта. Но, это получается ... работа выполнена ...? – 2013-03-01 06:05:52

9

Пока я не был действительно обеспокоен производительности, я хотел бы использовать функцию, которая принимает базу и возвращает его матч:

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

Если я был обеспокоен производительностью, я бы определил базу как одну четверть байта. 0 будет представлять A, 1 будет представлять G, 2 будет представлять C, а 3 будет представлять T. Тогда я бы упаковал 4 байт в байт и, чтобы получить их пары, я бы просто взял дополнение.

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; 
} 
+6

Несвязанный, но вы переполняете поток. – Rapptz

1

пар оснований = { "Т": "А", "А": "Т", "G": "С", "С": " G "} Что бы вы использовали?

Может быть:

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

;-)

14

Во время использования 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 ГБ.

+0

Но это все еще нуждается в линейном времени поиска для преобразования базовой пары в базовую пару. – perreal

+0

@perreal. Если «Линейное время поиска» означает «O (1)», то да, это все помещение O (1), а также максимально сжато для очень немного усилия. – 2013-03-01 06:33:24

+0

@perreal Не могли бы вы объяснить, как это линейное время? Поистине интересно. – Rapptz

33

Вы можете использовать следующий синтаксис:

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

Только в C++ 11. – congusbongus

1

Это самое быстрое, самое простое, самое маленькое космическое решение, о котором я могу думать. Хороший оптимизирующий компилятор даже удалит стоимость доступа к массивам пар и имен. Это решение работает одинаково хорошо в С.

#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

Но это решение предполагает, что ввод поступает как числа 0, 1, 2, 3, а не символы ASCII. Вам все равно придется выполнить сопоставление ввода, правильно? – jogojapan

+1

Хорошая точка. Я исправил его с самым быстрым отображением, о котором я мог думать, и более красивым, но, возможно, более медленным отображением на основе коммутаторов. –

Смежные вопросы