如何为一长串整数创建优化的迭代器?
How to create an optimized iterator for a long list of integers?
假设我有一个非常大的整数列表,占用了大量内存。如果列表的整数以偶数递增,我就可以轻松地将列表表示为一个相对不占用内存的迭代器。但是对于更复杂的模式,将这个列表表示为迭代器会变得更加困难。
是否有 Python 包可以分析整数列表和 return 一个 "optimized" 迭代器?或者我可以研究实现此目标的方法?
这很简单 - 只需用生成器包装过滤后的迭代器,例如:
for i in (_ for _ in range(int(1e7)) if str(_)==str(_)[::-1]):
if str(i**2)==str(i**2)[::-1]:
print(i)
发电机正是您要找的。您可以将所有自定义逻辑封装在里面。这个问题有点含糊,所以可能有助于了解这是否对您有帮助
def moreDataExists(index):
# Your stop condition
return True
def getNextIndex(index):
# Your complicated pattern of going from one index to the next.
return index
def generator(yourData):
index = None
while moreDataExists(index):
index = getNextIndex(index)
yield yourData[index]
for d in generator(data):
doSomethingWith(d)
我的概念证明,使用 lzma library (backport for python 2) 压缩到内存。您可以使用磁盘上的文件代替内存缓冲区:
import io
import random
import struct
import sys
from backports import lzma
# Create array of integers with some duplicates
data = []
for i in xrange(0, 2000):
data += [random.randint(-sys.maxint, sys.maxint)] * random.randint(0, 500)
print('Uncompressed: {}'.format(len(data)))
buff = io.BytesIO()
fmt = 'i' # check https://docs.python.org/3/library/struct.html#format-characters
lzma_writer = lzma.LZMAFile(buff, 'wb')
for i in data:
lzma_writer.write(struct.pack(fmt, i))
lzma_writer.close()
print('Compressed: {}'.format(len(buff.getvalue())))
buff.seek(0)
lzma_reader = lzma.LZMAFile(buff, 'rb')
size_of = struct.calcsize(fmt)
def generate():
r = lzma_reader.read(size_of)
while len(r) != 0:
yield struct.unpack(fmt, r)[0]
r = lzma_reader.read(size_of)
# Test if it is same array
res = list(generate())
print res == data
结果:
Uncompressed: 496225
Compressed: 11568
True
我同意 Efron Licht 的观点,显然:这完全取决于要压缩的特定列表的复杂性(更不用说 'compress')。除非您的列表足够简单以表示为生成器,否则您唯一的选择是使用 Bartek Jablonski 答案。
假设我有一个非常大的整数列表,占用了大量内存。如果列表的整数以偶数递增,我就可以轻松地将列表表示为一个相对不占用内存的迭代器。但是对于更复杂的模式,将这个列表表示为迭代器会变得更加困难。
是否有 Python 包可以分析整数列表和 return 一个 "optimized" 迭代器?或者我可以研究实现此目标的方法?
这很简单 - 只需用生成器包装过滤后的迭代器,例如:
for i in (_ for _ in range(int(1e7)) if str(_)==str(_)[::-1]):
if str(i**2)==str(i**2)[::-1]:
print(i)
发电机正是您要找的。您可以将所有自定义逻辑封装在里面。这个问题有点含糊,所以可能有助于了解这是否对您有帮助
def moreDataExists(index):
# Your stop condition
return True
def getNextIndex(index):
# Your complicated pattern of going from one index to the next.
return index
def generator(yourData):
index = None
while moreDataExists(index):
index = getNextIndex(index)
yield yourData[index]
for d in generator(data):
doSomethingWith(d)
我的概念证明,使用 lzma library (backport for python 2) 压缩到内存。您可以使用磁盘上的文件代替内存缓冲区:
import io
import random
import struct
import sys
from backports import lzma
# Create array of integers with some duplicates
data = []
for i in xrange(0, 2000):
data += [random.randint(-sys.maxint, sys.maxint)] * random.randint(0, 500)
print('Uncompressed: {}'.format(len(data)))
buff = io.BytesIO()
fmt = 'i' # check https://docs.python.org/3/library/struct.html#format-characters
lzma_writer = lzma.LZMAFile(buff, 'wb')
for i in data:
lzma_writer.write(struct.pack(fmt, i))
lzma_writer.close()
print('Compressed: {}'.format(len(buff.getvalue())))
buff.seek(0)
lzma_reader = lzma.LZMAFile(buff, 'rb')
size_of = struct.calcsize(fmt)
def generate():
r = lzma_reader.read(size_of)
while len(r) != 0:
yield struct.unpack(fmt, r)[0]
r = lzma_reader.read(size_of)
# Test if it is same array
res = list(generate())
print res == data
结果:
Uncompressed: 496225
Compressed: 11568
True
我同意 Efron Licht 的观点,显然:这完全取决于要压缩的特定列表的复杂性(更不用说 'compress')。除非您的列表足够简单以表示为生成器,否则您唯一的选择是使用 Bartek Jablonski 答案。