开发者

Arithmetic Progression in Python without storing all the values

I'm trying to represent an array of evenly spaced floats, an arithmetic progression, starting at a0 and with elements a0, a0 + a1, a0 + 2a1, a0 + 3a1, ... This is what numpy's arange() method does, but it seems to allocate memory for the whole array object and I'd like to do it using an iterator class which just stores a0, a1 and n (the total number of elements, which might be large). Does anything that does this already exist in the standard Python packages? I couldn't find it so, ploughed ahead with:

class mylist():
    def __init__(self, n, a0, a1):
        self._n = n
        self._a0 = a0
        self._a1 = a1

    def __getitem__(self, 开发者_开发知识库i):
        if i < 0 or i >= self._n:
            raise IndexError
        return self._a0 + i * self._a1

    def __iter__(self):
        self._i = 0
        return self

    def next(self):
        if self._i >= self._n:
            raise StopIteration
        value = self.__getitem__(self._i)
        self._i += 1
        return value

Is this a sensible approach or am I revinventing the wheel?


Well, one thing that you are doing wrong is that it should be for i, x in enumerate(a): print i, x.

Also, I'd probably use a generator method instead of the hassle with the __iter__ and next() methods, especially because your solution wouldn't allow you to iterate over the same mylist twice at the same time with two different iterators (as self._i is local to the class).

This is probably a better solution which gives you random access as well as an efficient iterator. The support for the in and len operators are thrown in as a bonus :)

class mylist(object):
    def __init__(self, n, a0, a1, eps=1e-8):
        self._n = n
        self._a0 = a0
        self._a1 = a1
        self._eps = eps

    def __contains__(self, x):
        y = float(x - self._a0) / self._a1
        return 0 <= int(y) < self._n and abs(y - int(y)) < self._eps

    def __getitem__(self, i):
        if 0 <= i < self._n:
            return self._a0 + i * self._a1
        raise IndexError

    def __iter__(self):
        current = self._a0
        for i in xrange(self._n):
             yield current
             current += self._a1

    def __len__(self):
        return self._n


Other answers answer the immediate problem. Note that if all you want is an iterator and you don't need random access, there's no need to write a whole iterator class.

def mylist(n, a0, a1):
    for i in xrange(n):
        yield a0 + i*a1


Only for reasons that are probably obvious to someone out there, iterating over mylist: for i,x in enumerate(a): print i,a doesn't return the values I expect but just a whole lot of references to the mylist instance. What am I doing wrong?

The culprit is print i,a. You are printing a, which is an array. You ought to print x instead. Chane this line to:

print i,x

Also a couple of things:

  1. Change you class name to TitleCase. For e.g. class MyList or class Mylist.
  2. It is a good idea to inherit from object if you are using Python 2.x. So class MyList(object): ...


You're enumerating over a, so printing it will print a lot of references to it. Print x instead.


Yes, there's a built-in generator for this (Python 2.7 and up):

import itertools
mygen = itertools.count(a0,a1)

If you don't have Python 2.7 yet (Python 2.4 and up):

import itertools
mygen = (a0 + a1*i for i in itertools.count())
0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜