2013-03-01 45 views
23

Di chuyển một số mã từ Python sang C++.Từ điển đơn giản trong C++

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

Bản đồ suy nghĩ có thể quá mức cần thiết? Bạn sẽ sử dụng cái gì?

+8

Tại sao bản đồ có thể quá mức cần thiết? – ForEveR

+0

Bạn định làm gì với họ? – bchurchill

+0

Tôi có thể định nghĩa một bản đồ là hằng số với các giá trị cơ bản bằng cách nào đó trong lớp definiton không? – y2k

Trả lời

13

Nếu bạn là thành tối ưu hóa, và giả định đầu vào luôn luôn là một trong bốn nhân vật, chức năng dưới đây có thể là đáng thử như một sự thay thế cho bản đồ :

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

Nó hoạt động dựa trên thực tế là bạn đang đối phó với hai cặp đối xứng. Các công việc có điều kiện để phân biệt cặp A/T với G/C ('G' và 'C' xảy ra để có bit chung thứ hai ít quan trọng nhất). Các arithmetics còn lại thực hiện ánh xạ đối xứng. Nó dựa trên thực tế là a = (a + b) - b là đúng cho bất kỳ a, b.

+0

Tư duy thực sự tốt. – y2k

+0

@ WHOEVENCARES Tôi không chắc liệu nó có nhanh hơn điều kiện thuần túy Benjamin Lindley được đề xuất hay không. Tuy nhiên, ít nhất phần trừ của hàm của tôi có thể được thực hiện trong một thanh ghi vector cho một vài ký tự song song. – jogojapan

7

Một bảng ra khỏi mảng char:

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

Không bằng python dict anyway ... Nhưng, tất cả phụ thuộc vào cách sử dụng ... – ForEveR

+1

Đó là một bản đồ rất lạ. – Rapptz

+0

Đây là một bản đồ vô cùng lãng phí. Nhưng, nó được ... công việc làm ...? –

9

Cho đến khi tôi đã thực sự lo ngại về hiệu suất, tôi sẽ sử dụng một chức năng, mà phải mất một cơ sở và trả về trận đấu của nó:

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

Nếu tôi quan tâm đến hiệu suất, tôi sẽ xác định một cơ sở là một phần tư của một byte. 0 sẽ đại diện cho A, 1 sẽ đại diện cho G, 2 sẽ đại diện cho C, và 3 sẽ đại diện cho T. Sau đó, tôi sẽ đóng gói 4 căn cứ vào một byte, và để có được cặp của họ, tôi chỉ đơn giản là sẽ bổ sung.

4

Đây là giải pháp bản đồ:

#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

Không liên quan nhưng bạn đang tràn ngập luồng. – Rapptz

1

BASEPAIRS = { "T": "A", "A": "T", "G": "C", "C": " G "} Bạn sẽ sử dụng cái gì?

Có thể:

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

;-)

14

Trong khi sử dụng một std::map được tốt hoặc sử dụng một bảng char 256 có kích thước sẽ là tốt, bạn có thể tiết kiệm cho mình một số lượng lớn không gian đau đớn chỉ cần sử dụng một số enum. Nếu bạn có C++ 11 tính năng, bạn có thể sử dụng enum class cho mạnh gõ:

// 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 
}; 

Cách sử dụng trở nên đơn giản:

int main (int argc, char* argv[]) { 
    BasePair bp = BasePair::A; 
    BasePair complimentbp = Complimentary[(int)bp]; 
} 

Nếu đây là quá nhiều cho bạn, bạn có thể xác định một số người giúp đỡ để lấy con người có thể đọc được các ký tự ASCII và cũng để có được những lời khen cặp base vì vậy bạn không làm (int) phôi tất cả các thời gian:

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 ]; 
} 

đó là sạch, nó đơn giản, và nó efficie nt.

Bây giờ, đột nhiên, bạn không có bảng 256 byte. Bạn cũng không lưu trữ các ký tự (mỗi byte 1 byte), và do đó nếu bạn đang viết nó vào một tệp, bạn có thể viết 2 bit cho mỗi cặp Cơ sở thay vì 1 byte (8 bit) cho mỗi cặp cơ sở. Tôi đã phải làm việc với Bioinformatics tập tin lưu trữ dữ liệu như là 1 nhân vật từng. Lợi ích là nó có thể đọc được. Con là những gì nên có được một tập tin 250 MB đã kết thúc lên lấy 1 GB không gian. Phong trào và lưu trữ và sử dụng là một cơn ác mộng. Của coursse, 250 MB đang được hào phóng khi chiếm ngay cả DNA Worm. Không có con người nào được đọc thông qua 1 GB giá trị của các cặp base dù sao đi nữa.

+0

Nhưng điều này vẫn cần thời gian tra cứu tuyến tính để chuyển đổi cặp char sang base – perreal

+0

@perreal Nếu theo "Thời gian tra cứu tuyến tính" nghĩa là 'O (1)', thì có, toàn bộ tiền đề này là O (1) và cũng được nén tối đa rất ít nỗ lực. –

+0

@perreal Bạn có thể giải thích đây là thời gian tuyến tính không? Thực sự quan tâm. – Rapptz

33

Bạn có thể sử dụng cú pháp sau:

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

Chỉ trong C++ 11. – congusbongus

1

Đây là giải pháp không gian nhỏ nhất, đơn giản nhất, nhanh nhất mà tôi có thể nghĩ đến. Một trình biên dịch tối ưu hóa tốt thậm chí sẽ loại bỏ chi phí truy cập vào các mảng và các mảng tên. Giải pháp này hoạt động tốt như nhau trong 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 [] là một hàm ascii char nhanh đến Base (nghĩa là giữa 0 và 3 bao gồm) tra cứu hơi xấu xí. Một trình biên dịch tối ưu hóa tốt sẽ có thể xử lý base2() nhưng tôi không chắc chắn nếu có.

+0

Nhưng giải pháp này giả định đầu vào là số 0, 1, 2, 3, chứ không phải ký tự ASCII. Bạn vẫn phải thực hiện ánh xạ đầu vào, đúng không? – jogojapan

+1

Điểm tốt. Tôi đã sửa nó với ánh xạ nhanh nhất mà tôi có thể nghĩ đến, và một bản đồ dựa trên chuyển đổi đẹp hơn nhưng có thể chậm hơn. –