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ì?
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ì?
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.
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';
/* .... */
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.
Đâ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;
}
Không liên quan nhưng bạn đang tràn ngập luồng. – Rapptz
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]
;-)
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.
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
@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. –
@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
Bạn có thể sử dụng cú pháp sau:
std::map<char, char> my_map = {
{ 'A', '1' },
{ 'B', '2' },
{ 'C', '3' }
};
Chỉ trong C++ 11. – congusbongus
Đâ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ó.
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
Đ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. –
Tại sao bản đồ có thể quá mức cần thiết? – ForEveR
Bạn định làm gì với họ? – bchurchill
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