The comments referring to using a "lazy" number likely mean you could redefine retrieval of the value(s) such that at the point of reading the value by-index (or while iterating), the increment is added, rather than going through every member initially
You likely want to avoid
class LazyIncrementList(list):
""" implement a list which can lazily increment members
"""
def __init__(self, /, *args, **kwargs):
self.period = kwargs.pop("period", None) # every Nth value
self.increment = kwargs.pop("increment", None) # to add or subtract
self.offset = kwargs.pop("offset", 0) # roll the period
if any((self.period, self.increment)) and not all((self.period, self.increment)):
raise TypeError(f"period({period}) and increment({increment}) must be given together if either is provided")
# consider just all() or raise for None as caller could just use a normal list
super().__init__(*args, **kwargs) # list init
def __repr__(self):
return f"{type(self).__name__}<{len(self)}>"
def __getitem__(self, idx, /):
value = super().__getitem__(idx)
if self.period is not None and (idx + self.offset) % self.period == 0:
return value + self.increment
return value
def __iter__(self):
if self.period is None:
return super().__iter__()
return iter(self[n] for n in range(len(self)))
def __contains__(self, key):
if self.period is None:
return super().__contains__()
# caution: this will be much slower than a list!
# consider NotImplementedError or internal set() wrapper for small spreads
for value in self:
if key == value:
return True
return False
Example Usage
>>> list(LazyIncrementList((1, 2, 3), period=5, increment=10, offset=5))
[11, 2, 3]
>>> l = LazyIncrementList((3.0, 3.1, 3.2, 3.3, 3.4, 3.5, 3.6, 3.7, 3.8, 3.9), period=8, increment=0.5)
>>> l
LazyIncrementList<10>
>>> list(l)
[3.5, 3.1, 3.2, 3.3, 3.4, 3.5, 3.6, 3.7, 4.3, 3.9]
>>> l[0], l[8]
(3.5, 4.3)
>>> 3.8 in l
False
>>> 4.3 in l
True
>>> l[8] = 12.1
>>> l[8]
12.6
>>> l[8]
12.6
Note that with a few million values and if you eventually use every value, just looping and incrementing is probably fine, surprisingly quick (a few seconds at most), and also obvious.. however, there might be lots of middle-ground, such as if you could lazily read the values from disk by-lines .. but we need more details about your problem to know if this would be an improvement
with open(path) as fh:
for index, line in enumerate(fh):
value = float(line)
if index % 8 == 0:
value += 0.5
yield data
Finally, what's "best" would change further if you had very large memory objects rather than humble floats, say images you were manipulating, if your values were located on a slow network resource, or there was too much data for your system memory .. then you might consider breaking the work up into jobs for threads or an async pool work through them or calling out to a database