Pergunta

É possível usar numpy.memmap para mapear uma grande variedade baseada em disco de cordas na memória?

Eu sei que isso pode ser feito para carros alegóricos e similares, mas esta questão é especificamente sobre strings.

Estou interessado em soluções para strings de comprimento fixo e variável.

A solução é livre para ditar qualquer formato de arquivo razoável.

Foi útil?

Solução

Se todas as strings tiverem o mesmo comprimento, como sugerido pelo termo "array", isso é facilmente possível:

a = numpy.memmap("data", dtype="S10")

seria um exemplo para strings de comprimento 10.

Editar:Como aparentemente as strings não têm o mesmo comprimento, você precisa indexar o arquivo para permitir o acesso ao item O(1).Isso requer a leitura de todo o arquivo uma vez e o armazenamento dos índices iniciais de todas as strings na memória.Infelizmente, não acho que exista uma maneira pura de indexação do NumPy sem criar primeiro um array do mesmo tamanho do arquivo na memória.Porém, esse array pode ser eliminado após a extração dos índices.

Outras dicas

A opção mais flexível seria mudar para um banco de dados ou alguma outra estrutura de arquivos em disco mais complexa.

No entanto, provavelmente há um bom motivo para você preferir manter as coisas como um arquivo de texto simples...

Como você tem controle de como os arquivos são criados, uma opção é simplesmente gravar um segundo arquivo que contenha apenas as posições iniciais (em bytes) de cada string no outro arquivo.

Isso exigiria um pouco mais de trabalho, mas você poderia essencialmente fazer algo assim:

class IndexedText(object):
    def __init__(self, filename, mode='r'):
        if mode not in ['r', 'w', 'a']:
            raise ValueError('Only read, write, and append is supported')
        self._mainfile = open(filename, mode)
        self._idxfile = open(filename+'idx', mode)

        if mode != 'w':
            self.indicies = [int(line.strip()) for line in self._idxfile]
        else:
            self.indicies = []

    def __enter__(self):
        return self

    def __exit__(self, type, value, traceback):
        self._mainfile.close()
        self._idxfile.close()

    def __getitem__(self, idx):
        position = self.indicies[idx]
        self._mainfile.seek(position)
        # You might want to remove the automatic stripping...
        return self._mainfile.readline().rstrip('\n')

    def write(self, line):
        if not line.endswith('\n'):
            line += '\n'
        position = self._mainfile.tell()
        self.indicies.append(position)
        self._idxfile.write(str(position)+'\n')
        self._mainfile.write(line)

    def writelines(self, lines):
        for line in lines:
            self.write(line)


def main():
    with IndexedText('test.txt', 'w') as outfile:
        outfile.write('Yep')
        outfile.write('This is a somewhat longer string!')
        outfile.write('But we should be able to index this file easily')
        outfile.write('Without needing to read the entire thing in first')

    with IndexedText('test.txt', 'r') as infile:
        print infile[2]
        print infile[0]
        print infile[3]

if __name__ == '__main__':
    main()
Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top