Python: как нарезать / хранить свои данные в фиксированном буфере класса? - PullRequest
2 голосов
/ 17 октября 2010

All

Как вы знаете, с помощью python iter мы можем использовать iter.next () для получения следующего элемента данных. возьмите список например:

l =  [x for x in range(100)]
itl = iter(l)
itl.next()            # 0
itl.next()            # 1

Теперь я хочу, чтобы в буфере можно было хранить * общие данные, указываемые на нем ** * срез фиксированного размера, используйте приведенный выше список для демонстрации моего вопроса.

class IterPage(iter, size):
      # class code here

itp = IterPage(itl, 5)

что я хочу это

print itp.first()   # [0,1,2,3,4]
print itp.next()    # [5,6,7,8,9]
print itp.prev()    # [0,1,2,3,4]
len(itp)            # 20   # 100 item / 5 fixed size = 20    
print itp.last()   # [96,97,98,99,100]


for y in itp:           # iter may not support "for" and len(iter) then something alike code also needed here  
    print y
[0,1,2,3,4]
[5,6,7,8,9]
...
[96,97,98,99,100]

это не домашнее задание, но, как новичок в питоне, мало знакомый с разработкой класса iter, может кто-нибудь поделиться со мной, как кодировать класс "IterPage" здесь?

Кроме того, с помощью ответов ниже, которые я обнаружил, если необработанные данные, которые я хочу разрезать, очень большие, например, текстовый файл 8 Гига или таблица записей 10 ^ 100 в базе данных, он может не прочитать все их список - у меня нет так много физических воспоминаний. Возьмите фрагмент в документе Python, например:

http://docs.python.org/library/sqlite3.html#

>>> c = conn.cursor()
>>> c.execute('select * from stocks order by price')
>>> for row in c:
...    print row
...
(u'2006-01-05', u'BUY', u'RHAT', 100, 35.14)
(u'2006-03-28', u'BUY', u'IBM', 1000, 45.0)
(u'2006-04-06', u'SELL', u'IBM', 500, 53.0)
(u'2006-04-05', u'BUY', u'MSOFT', 1000, 72.0)

Если здесь у нас есть около 10 ^ 100 записей, то в таком случае возможно ли хранить только те строки / записи, которые я хочу, для этого класса с itp = IterPage(c, 5)? если я вызову itp.next (), itp может просто получить следующие 5 записей из базы данных?

Спасибо!

PS: я получил подход по ссылке ниже: http://code.activestate.com/recipes/577196-windowing-an-iterable-with-itertools/

и я также обнаружил, что кто-то хочет создать функцию itertools.iwindow (), однако она была отклонена. http://mail.python.org/pipermail/python-dev/2006-May/065304.html

Ответы [ 2 ]

4 голосов
/ 17 октября 2010

Поскольку вы спрашивали о дизайне, я напишу немного о том, что вы хотите - это не итератор.

Определяющим свойством итератора является то, что он только поддерживает итерацию, а не произвольный доступ. Но такие методы, как .first и .last, осуществляют произвольный доступ, поэтому вы запрашиваете не итератор.

Конечно, есть контейнеры, которые позволяют это. Они называются последовательностями, и самый простой из них - list. Это .first метод записывается как [0], а .last это [-1].

Итак, вот такой объект, который разрезает заданную последовательность. Он хранит список slice объектов, который Python использует для вырезания частей списка. Методы, которые класс должен реализовать, чтобы быть последовательностью, определяются базовым классом abstact Sequence. Хорошо наследовать от него, потому что он выдает ошибки, если вы забыли реализовать требуемый метод.

from collections import Sequence

class SlicedList(Sequence):
    def __init__(self, iterable, size):
        self.seq = list(iterable)
        self.slices = [slice(i,i+size) for i in range(0,len(self.seq), size)]

    def __contains__(self, item):
        # checks if a item is in this sequence
        return item in self.seq

    def __iter__(self):
        """ iterates over all slices """
        return (self.seq[slice] for slice in self.slices)

    def __len__(self):
        """ implements len( .. ) """
        return len(self.slices)

    def __getitem__(self, n):
        # two forms of getitem ..
        if isinstance(n, slice):
            # implements sliced[a:b]
            return [self.seq[x] for x in self.slices[n]]
        else:
            # implements sliced[a]
            return self.seq[self.slices[n]]

s = SlicedList(range(100), 5)

# length
print len(s) # 20

#iteration
print list(s) # [[0, 1, 2, 3, 4], [5, 6, 7, 8, 9], ... , [95, 96, 97, 98, 99]]
# explicit iteration:
it = iter(s)
print next(it) # [0, 1, 2, 3, 4]

# we can slice it too
print s[0], s[-1] # [0, 1, 2, 3, 4] [95, 96, 97, 98, 99]
# get the first two
print s[0:2] # [[0, 1, 2, 3, 4], [5, 6, 7, 8, 9]]
# every other item
print s[::2] # [[0, 1, 2, 3, 4], [10, 11, 12, 13, 14], [20, 21, 22, 23, 24], ... ]

Теперь, если вам действительно нужны такие методы, как .start (что в любом случае, просто подробный способ для [0]), вы можете написать класс, подобный этому:

class Navigator(object):    
    def __init__(self, seq):
        self.c = 0
        self.seq = seq

    def next(self):
        self.c +=1
        return self.seq[self.c]

    def prev(self):
        self.c -=1
        return self.seq[self.c]

    def start(self):
        self.c = 0
        return self.seq[self.c]

    def end(self):
        self.c = len(self.seq)-1
        return self.seq[self.c]

n = Navigator(SlicedList(range(100), 5))

print n.start(), n.next(), n.prev(), n.end()
3 голосов
/ 17 октября 2010

Необработанные данные, которые я хочу разрезать, очень большие, например, текстовый файл 8 Гига ... Возможно, я не смогу прочитать их все в списке - у меня не так много физической памяти.В таком случае, возможно ли получить только те строки / записи, которые мне нужны по этому классу?

Нет, в сущности, класс, первоначально предложенный ниже, преобразует итератор в список, что делает его 100%бесполезен для вашей ситуации.

Просто используйте идиому группировщика (также упомянутую ниже).Вы должны уметь запоминать предыдущие группы.Для экономии памяти сохраняйте только те предыдущие группы, которые вам нужны.Например, если вам нужна только самая последняя предыдущая группа, вы можете сохранить ее в одной переменной: previous_group.

Если вам нужны 5 самых последних предыдущих групп, вы можете использовать коллекции ..deque с максимальным размером 5.

Или вы можете использовать идиому window, чтобы получить скользящее окно из n групп групп ...

Учитываячто вы сказали нам до сих пор, я бы не стал определять класс для этого, потому что я не вижу много многократно используемых элементов решения.


В основном то, что вы хотите, можно сделать с помощью grouper idiom :

In [22]: l =  xrange(100)    
In [23]: itl=iter(l)    
In [24]: import itertools    
In [25]: for y in itertools.izip(*[itl]*5):
   ....:     print(y)
(0, 1, 2, 3, 4)
(5, 6, 7, 8, 9)
(10, 11, 12, 13, 14)
...
(95, 96, 97, 98, 99)

Вызов next не проблема:

In [28]: l =  xrange(100)

In [29]: itl=itertools.izip(*[iter(l)]*5)

In [30]: next(itl)
Out[30]: (0, 1, 2, 3, 4)

In [31]: next(itl)
Out[31]: (5, 6, 7, 8, 9)

Но создание метода previous является большой проблемой, потому что итераторы нене работает таким образом.Итераторы предназначены для создания значений без запоминания прошлых значений.Если вам нужны все прошлые значения, тогда вам нужен список, а не итератор:

In [32]: l =  xrange(100)
In [33]: ll=list(itertools.izip(*[iter(l)]*5))

In [34]: ll[0]
Out[34]: (0, 1, 2, 3, 4)

In [35]: ll[1]
Out[35]: (5, 6, 7, 8, 9)

# Get the last group
In [36]: ll[-1]
Out[36]: (95, 96, 97, 98, 99)

Теперь получение предыдущей группы - это просто вопрос отслеживания индекса списка.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...