2015-04-28 3 views
4

Код, который я недавно работал, был найден вокруг 200MB памяти для запуска, и я в тупике о том, зачем это нужно.Потребление памяти списков списков python

В основном он отображает текстовый файл в список, в котором каждый символ в файле представляет собой собственный список, содержащий символ, и как часто он показывается (начиная с нуля) в качестве двух элементов.

Так 'abbac...' будет [['a','0'],['b','0'],['b','1'],['a','1'],['c','0'],...]

Для текстового файла длиной 1 миллиона символов, оно используется 200MB.

Это разумно или это было что-то еще, что делал мой код? Если это разумно, было ли это из-за большого количества списков? Будет [a,0,b,0,b,1,a,1,c,0...] займет значительно меньше места?

+3

Важно ли иметь несколько записей для каждого символа? В вашем примере было бы достаточно иметь '[a, 2], [b, 2], [c, 1] ...', просто подсчитывая вхождения для каждого символа? – ODiogoSilva

+4

Как вы оценили использование вашей памяти? –

+0

Я немного нерешительно смотрю, как это задание, которое еще предстоит закончить. Это необходимо? – user2998454

ответ

2

Если вам не нужен сам список, я полностью соглашаюсь с решением @ Lattyware на использование генератора.

Однако, если это не вариант, возможно, вы можете сжать данные в своем списке без потери информации, сохранив только позиции для каждого символа в файле.

import random 
import string 

def track_char(s): 
    # Make sure all characters have the same case 
    s = s.lower() 
    d = dict((k, []) for k in set(s)) 
    for position, char in enumerate(s): 
     d[char].append(position) 
    return d 

st = ''.join(random.choice(string.ascii_uppercase) for _ in range(50000)) 
d = track_char(st) 

len(d["a"]) 

# Total number of occurrences of character 2 
for char, vals in d.items(): 
    if 2 in vals: 
     print("Character %s has %s occurrences" % (char,len(d[char])) 
Character C has 1878 occurrences 

# Number of occurrences of character 2 so far 
for char, vals in d.items(): 
    if 2 in vals: 
     print("Character %s has %s occurrences so far" % (char, len([x for x in d[char] if x <= 2)) 
Character C has 1 occurrences so far 

Таким образом, нет необходимости дублировать строку символов, каждый раз, когда есть возникновение, и хранить информацию о всех их вхождений.

Для сравнения размера объекта из исходного списка или этот подход, вот тест

import random 
import string 
from sys import getsizeof 

# random generation of a string with 50k characters 
st = ''.join(random.choice(string.ascii_uppercase) for _ in range(50000)) 

# Function that returns the original list for this string 
def original_track(s): 
    l = [] 
    for position, char in enumerate(s): 
     l.append([char, position]) 
    return l 

# Testing sizes 
original_list = original_track(st) 
dict_format = track_char(st) 

getsizeof(original_list) 
406496 
getsizeof(dict_format) 
1632 

Как вы можете видеть, dict_format примерно 250х раз меньше по размеру. Однако это различие в размерах должно быть более выраженным в больших строках.

+0

Большое спасибо. Буду ли я прав, говоря, что это займет около половины пространства «[a, 0, b, 0, b, 1, a, 1, c, 0 ...]», поскольку буквы появляются только один раз но все еще нужно иметь n элементов в списках? – user2998454

+1

Это зависит от размера строки. Я обновляю сообщение с некоторыми тестами – ODiogoSilva

+0

argh на второй мысли, мой список по-прежнему необходим, потому что только «[a, 0, b, 0, b, 1, a, 1, c, 0 ...]» может сказать сколько раз n-я буква в файле показывалась в постоянное время. Если я не ошибаюсь. – user2998454

1

Когда речь идет об использовании памяти и списках, одним из лучших способов уменьшить использование памяти является исключение списков вообще - Python имеет большую поддержку итераторов в виде генераторов. Если вы можете создать генератор вместо создания списка, вы сможете сделать что-то подобное с очень небольшим использованием памяти. Конечно, это зависит от того, что вы делаете с данными позже (скажем, вы пишете эту структуру в файл, вы можете делать это по частям, а не хранить всю вещь сразу).

from collections import Counter 

def charactersWithCounts(): 
    seen = Counter() 
    for character in data: 
     yield (character, seen[character]) 
     seen[character] += 1 
Смежные вопросы