Python 函数将字符串存储为int

Python 函数将字符串存储为int,python,bioinformatics,dna-sequence,Python,Bioinformatics,Dna Sequence,我有一个固定的32位,用来存储尽可能多的DNA。由于只有4种组合,因此存储DNA‘A’、‘C’、‘G’或‘T’的1个字符所需的空间量为2位00、01、10、11 要存储最多2个字符,因此,A、C、G、T、AA、AC、…、GG有20种可能的组合,我们可以使用函数4**x+1-2/4-1计算出来,其中x是我们要存储的DNA的最大长度。因此,16个DNA字符将有5726623060个组合,但在32位中,我最多只能存储4294967296个数字2**32 长话短说,在32位中,一个人可以存储的可变长度D

我有一个固定的32位,用来存储尽可能多的DNA。由于只有4种组合,因此存储DNA‘A’、‘C’、‘G’或‘T’的1个字符所需的空间量为2位00、01、10、11

要存储最多2个字符,因此,A、C、G、T、AA、AC、…、GG有20种可能的组合,我们可以使用函数4**x+1-2/4-1计算出来,其中x是我们要存储的DNA的最大长度。因此,16个DNA字符将有5726623060个组合,但在32位中,我最多只能存储4294967296个数字2**32

长话短说,在32位中,一个人可以存储的可变长度DNA的最大数量是15个字母1431655764个组合

所以,下一步是制作一个函数,它将多达15个DNA字母作为一个字符串,并将其转换为一个数字。哪一个数字“A”可以是0,也可以是1,也可以是1332904,这并不重要,只要我们可以反转函数,稍后将数字返回到“A”

我开始通过制作包含1431655764个元素的键值对字典来解决这个问题,但很快就耗尽了RAM。这就是为什么我需要一个从字符串到int的转换函数。

这是我的建议

如果存储字母需要2到30位,那么至少还有2位可以帮助您推断长度。始终在代表字符的位后添加1,并用零填充其余部分。这样,如果您查找位模式中的最后一个1,它将始终位于字符串末尾之后

例如


这应该明确地表示字符串,并允许您在32位中最多包含15个字符。

给定静态顺序,您可以将每个排列引用为表示其在序列中顺序的单个数字。然后,您可以在另一端转换词典,而不是构建词典

import itertools

def build_sequence(length):
    return itertools.product("ACTG", repeat=length)

def encode(sequence: str):
    seq = build_sequence(len(str))
    t_seq = list(sequence)  # to compare to seq
    for idx, s in enumerate(seq):
        if s == t_seq:
            return idx

def decode(e_sequence):
    max_length = math.ceil(math.log(e_sequence, 4))
    # max_length is the character count of ATCGs that e_sequence contains,
    #   since each sequence has 4**length elements
    seq = build_sequence(max_length)
    for _ in range(e_sequence):
        # skipping these is like indexing a list
        next(seq)
    return next(seq)
然后,您可以将该数字打包成一个较小的类型,并通过网络发送,再次解压缩,然后解码

import struct

packed = struct.pack("I", encode(some_sequence))
#  send it? I'm not sure what you're doing with it

rcvd_pack = b'SUUU'
unpacked = struct.unpack("I", rcvd_pack)
# becomes a tuple of the value
enc_seq = unpacked[0]

result = decode(enc_seq)

这应该可以让您构建16个字符的序列,并将它们打包到32位数据中。

使用Khelwood的信息,我用以下代码解决了它:

b = {'A':0b00,'C':0b01,'G':0b10,'T':0b11}
t = {'00':'A','01':'C','10':'G','11':'T'}

def binarize(string):
    result = 0
    for char in (string + 'G').ljust(16,'A'): result = (result << 2) + d[char]
    return result

def textualize(value):
    result = ''
    for twobits in [ format(value, '032b')[i:i+2] for i in range(0,32,2) ]:
        result += t[twobits]
    return result.rstrip('A')[:-1]

>>> binarize('TTTTTTTTTTTTTTT')
    4294967294

>>> textualize(4294967294)
    u'TTTTTTTTTTTTTTT'

我相信有一种更有效的方法来完成这一切,我想我需要这样做,因为我将编码和解码数十亿次,但现在它至少起作用:

一旦确定可以将每个字符存储在两位中,我不确定您遇到的困难是什么。你有代码吗?只有当字符串长度不变时,每个字母2位才有效。例如,在4位中,我可以用0000表示“AA”,但不能单独表示“A”。有20种DNA组合,只有16个值可以存储在4位中。在这种情况下,您有额外的信息,即字符串的长度,这将需要额外的空间进行编码。为什么您会拒绝投票,并提交一个没有先前解决方案的帖子的接近投票,并且没有任何原因!?因为你的问题归根结底是给我一个代码,这是一个愚蠢的提议,因为你试图在内存非常有限的环境中使用Python。这是一个坏主意,因为同样的原因,你不使用水彩画的数字。它变得邋遢了。使用一种不进行内存管理的语言谢谢你,亚当,我从了解代码的工作原理中学到了很多:我把它放在一个numpy数组中,但是我使用的struct与你描述的完全一样。唯一的问题是,当您浏览itertools.product时,编码15g需要很长时间。但它确实有效,而且很优雅。math.ceilmath.logseq,4是我的秘方:@J.J同意,是的。你应该可以用数学的方法来计算,但我没有时间去弄清楚这些案例是如何运作的。它将类似于二进制编码,但我认为是以4为基数而不是以2为基数?我数学不太清楚
b = {'A':0b00,'C':0b01,'G':0b10,'T':0b11}
t = {'00':'A','01':'C','10':'G','11':'T'}

def binarize(string):
    result = 0
    for char in (string + 'G').ljust(16,'A'): result = (result << 2) + d[char]
    return result

def textualize(value):
    result = ''
    for twobits in [ format(value, '032b')[i:i+2] for i in range(0,32,2) ]:
        result += t[twobits]
    return result.rstrip('A')[:-1]

>>> binarize('TTTTTTTTTTTTTTT')
    4294967294

>>> textualize(4294967294)
    u'TTTTTTTTTTTTTTT'