Как перебрать defaultdict (список) в Python? - PullRequest
2 голосов
/ 27 декабря 2011

Как перебрать defaultdict (список) в Python?Есть ли лучший способ иметь словарь списков в Python?Я попробовал нормальный iter(dict), но у меня есть ошибка:

>>> import para
>>> para.print_doc('./sentseg_en/essentials.txt')
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "para.py", line 31, in print_doc
    for para in iter(doc):
TypeError: iteration over non-sequence

Основной класс:

import para
para.print_doc('./foo/bar/para-lines.txt')

Para.pyc:

# -*- coding: utf-8 -*-
## Modified paragraph into a defaultdict(list) structure
## Original code from http://code.activestate.com/recipes/66063/
from collections import defaultdict
class Paragraphs:
    import sys
    reload(sys)
    sys.setdefaultencoding('utf-8')
    # Separator here refers to the paragraph seperator,
    #  the default separator is '\n'.
    def __init__(self, filename, separator=None):
        # Set separator if passed into object's parameter,
        #  else set default separator as '\n'
        if separator is None:
            def separator(line): return line == '\n'
        elif not callable(separator):
            raise TypeError, "separator argument must be callable"
        self.separator = separator
        # Reading lines from files into a dictionary of lists
        self.doc = defaultdict(list)
        paraIndex = 0
        with open(filename) as readFile:
            for line in readFile:
                if line == separator:
                    paraIndex+=1
                else:
                    self.doc[paraIndex].append(line)

# Prints out populated doc from txtfile
def print_doc(filename):
    text = Paragraphs(filename)
    for para in iter(text.doc):
        for sent in text.doc[para]:
            print "Para#%d, Sent#%d: %s" % (
                para, text.doc[para].index(sent), sent)

Например, ./foo/bar/para-lines.txt выглядит так:

This is a start of a paragraph.
foo barr
bar foo
foo foo
This is the end.

This is the start of next para.
foo boo bar bar
this is the end.

Вывод основного класса должен выглядеть следующим образом:

Para#1,Sent#1: This is a start of a paragraph.
Para#1,Sent#2: foo barr
Para#1,Sent#3: bar foo
Para#1,Sent#4: foo foo
Para#1,Sent#5: This is the end.

Para#2,Sent#1: This is the start of next para.
Para#2,Sent#2: foo boo bar bar
Para#2,Sent#3: this is the end.

Ответы [ 5 ]

4 голосов
/ 27 декабря 2011

Проблема с линией

for para in iter(doc):

означает, что doc является экземпляром Paragraph, а не defaultdict. Диктофон по умолчанию, который вы используете в методе __init__, выходит из области видимости и теряется. Так что вам нужно сделать две вещи:

  1. Сохраните doc, созданный в методе __init__, в качестве переменной экземпляра (например, self.doc).

  2. Либо сделайте Paragraphs сам итеративным (добавив метод __iter__), либо разрешите ему доступ к созданному объекту doc.

2 голосов
/ 27 декабря 2011

Рецепт, с которым вы связаны, довольно старый.Он был написан в 2001 году, до того, как в Python появились более современные инструменты, такие как itertools.groupby (представлен в Python2.4, , выпущенный в конце 2003 года ).Вот как может выглядеть ваш код, используя groupby:

import itertools
import sys

with open('para-lines.txt', 'r') as f:
    paranum = 0
    for is_separator, paragraph in itertools.groupby(f, lambda line: line == '\n'):
        if is_separator:
            # we've reached paragraph separator
            print
        else:
            paranum += 1
            for n, sentence in enumerate(paragraph, start = 1):
                sys.stdout.write(
                    'Para#{i:d},Sent#{n:d}: {s}'.format(
                        i = paranum, n = n, s = sentence))
0 голосов
/ 27 декабря 2011

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

doc = []
with open(filename) as readFile:
    para = []
    for line in readFile:
        if line == separator:
            doc.append(para)
            para = []
        else:
            para.append(line)
    doc.append(para)
0 голосов
/ 27 декабря 2011

Сбой, потому что у вас нет __iter__(), определенного в вашем классе Paragraphs, и затем попытайтесь вызвать iter(doc) (где doc - это экземпляр Paragraphs)

Чтобы быть повторяемым, класс должен иметь __iter__(), который возвращает итератор. Документы здесь .

0 голосов
/ 27 декабря 2011

Кажется, проблема в том, что вы перебираете класс Paragraphs, а не словарь. Кроме того, вместо перебора ключей и последующего доступа к записи словаря, рассмотрите возможность использования

for (key, value) in d.items():
...