2011-12-27 24 views
2

Pythonでdefaultdict(list)を反復処理するにはどうすればよいですか? Pythonでリストの辞書を使用するより良い方法はありますか? 私は通常のiter(dict)を試みたが、私はエラーが持っている:Pythonでdefaultdict(list)を反復処理する方法は?

>>> 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) 

例えばを

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. 

メインクラスの出力は次のようになります:このような./foo/bar/para-lines.txtルックスの

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. 

答えて

2

リンク先のレシピはかなり古いです。これはPythonがitertools.groupby(Python2.4で導入された、released in late 2003のような)のようなより現代的なツールを持つ前に2001年に書かれました。ここにあなたのコードが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

私は 'for'ループから抜け出すと、' paragraph'が範囲外になってしまうでしょうか?どのように段落を保持し、 'itertools.groupby'ループの外でそれにアクセスし続けますか? – alvas

+0

いいえ、 'paragraph'という名前は範囲外に出ません。 Pythonは、関数のためだけに、 'with'や' for'のようなブロック構造の新しいスコープをオープンしません。 – kindall

+0

'paragraph'はループのたびに新しい値に再割り当てされます。古い段落を残しておきたい場合は、 'paragraphs = []'リストをループの外側に定義し、各段落を 'paragraphs.append(paragraph)'ループの中に追加することができます。 – unutbu

0

問題は、あなたがあなたのParagraphsクラスではなく、辞書を反復処理しているということのようです。また、代わりにキーを反復処理して、辞書のエントリにアクセスする、あなたの段落クラスで__iter__()が定義されているし、その後ドキュメントが段落インスタンスです(iter(doc)を呼び出そうとしないので、それは失敗だ

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

を使用することを検討してください)。

反復可能にするには、反復子を返す__iter__()が必要です。 Docs here

4

あなたがライン

for para in iter(doc): 

を持っている問題は、docは、段落のインスタンスではなく、defaultdictであるということです。 __init__メソッドで使用するデフォルトのディクショナリが範囲外になり、失われます。 (例えば、self.doc

  1. 保存インスタンス変数として__init__方法で作成しdoc:だから、2つのことを行う必要があります。

  2. __iter__メソッドを追加することによって、Paragraphs自体を反復可能にするか、または作成したdocオブジェクトにアクセスさせることができます。

+0

私は[paraIndex] 'doc'と' 'self.doc' self.doc = defaultdict(リスト)で'と 'self.docを保存しようとしました。 append(行) '。しかし、同じ範囲外の問題が発生します。 – alvas

+0

@ 2er0:これは有効範囲ですが、 'docです。doc'(名前付けの問題もあるので、 'print_doc'では' doc'の代わりに 'paragraphs'のようなものを使うべきです)。 –

+0

ネーミングの問題に注目してくれてありがとうございます。しかし、私は 'self.doc'ソリューションとunutbuのループソリューションを組み合わせることができるかどうかを見てみましょう。 – alvas

0

ここではディクティブを使用している理由は考えられません。リストのリストははるかに簡単です。

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

私のtxtファイルは大きなtxtファイルになるので、入れ子にされたリストにアクセスすると時間がかかります。多分私は辞書の辞書が必要になるでしょう。辞書の辞書が必要な場合はどうすればよいですか? – alvas

+0

それはどのように続くのですか?ネストされたリストは、なぜディクテーションのdictよりも時間がかかりますと思いますか? –