2016-11-09 20 views
1

私はJSONファイルを持っており、次の10個のオブジェクトをファイル内ののリストを返す関数を作成したいと考えています。私はクラスFileProcessorとメソッドget_row()から始め、ファイルから単一のJSONオブジェクトを生成するジェネレータを返します。別のメソッドget_chunk()は、次の10個のオブジェクトを返す必要があります。ここでファイルからチャンクを生成

私がこれまで持っているものです。

class FileProcessor(object): 

    def __init__(self, filename): 
     self.FILENAME = filename 

    def get_row(self): 
     with open(os.path.join('path/to/file', self.FILENAME), 'r') as f: 
      for i in f: 
       yield json.loads(i) 

    def get_chunk(self): 
     pass 

私はこのように試してみたが、それは唯一の最初の10行ごとに時間を返します。

def get_chunk(self): 
     chunk = [] 
     consumer = self.consume() 
     for i in self.get_row(): 
      chunk.append(i) 
     return chunk  

get_chunk()を書き込む正しい方法は何ですか?

+0

標準ライブラリに含まれているjsonパーサがインクリメンタルロードをサポートしていませんか?それともそれを拡張することはできませんか? – SwiftsNamesake

+0

'FileProcessor.get_row'メソッドは正しく動作しますか? IOW、テキストファイル_保証の各行は完全なJSONオブジェクトですか? –

+0

@ PM2Ringはい、それは完全なJSONオブジェクトを返しています –

答えて

2

ここに、別のジェネレータから値を取得してリストに入れる単純なジェネレータがあります。あなたのFileProcessor.get_rowメソッドでうまくいくはずです。

def count(n): 
    for v in range(n): 
     yield str(v) 

def chunks(it, n): 
    while True: 
     yield [next(it) for _ in range(n)] 

for u in chunks(count(100), 12): 
    print(u) 

出力

['0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '10', '11'] 
['12', '13', '14', '15', '16', '17', '18', '19', '20', '21', '22', '23'] 
['24', '25', '26', '27', '28', '29', '30', '31', '32', '33', '34', '35'] 
['36', '37', '38', '39', '40', '41', '42', '43', '44', '45', '46', '47'] 
['48', '49', '50', '51', '52', '53', '54', '55', '56', '57', '58', '59'] 
['60', '61', '62', '63', '64', '65', '66', '67', '68', '69', '70', '71'] 
['72', '73', '74', '75', '76', '77', '78', '79', '80', '81', '82', '83'] 
['84', '85', '86', '87', '88', '89', '90', '91', '92', '93', '94', '95'] 

なお、この唯一の利回り完全な塊。前回出力した後

['96', '97', '98', '99'] 

を出力します

def chunks(it, n): 
    while True: 
     chunk = [] 
     for _ in range(n): 
      try: 
       chunk.append(next(it)) 
      except StopIteration: 
       yield chunk 
       return 
     yield chunk 

:それが問題だ場合、あなたはこれを行うことができます。 Antti Haapala

from itertools import islice 

def chunks(it, n): 
    while True: 
     a = list(islice(it, n)) 
     if not a: 
      return 
     yield a 

感謝をisliceについて私に思い出させるために:これを行うには


より良い方法は、部分的に、最終的なチャンクを処理するた、itertools.isliceを使用することです。 :)

+0

私は1つの答えを書くのに忙しかった、あなたは私にそれを打つ!私は 'map'を使用してジェネレータを作成していますので、いくつかのオプションを表示するために投稿すると思います。しかし私はあなたの答えが好きです。 – tdelaney

2

(注:PM 2Ringはそれに私を打ち負かす!)

はあなたのget_row方法が行を返さない - それはあなたがそれを反復処理として行が生成されますジェネレータを返します。 get_chunkの方法でfor i in self.get_row...を実行していることがわかります。厄介なことは、get_rowに電話するたびにファイルを再度開いて最初のオブジェクトを返すことです。 get_chunkの問題は、必要な行数を渡さず、forループをその数に制限しないことです。 get_chunkは、ファイル内のすべての行を取得します。

再考はどうですか?本当に必要なのは、線を読み、jsonを逆シリアル化するジェネレータだけです。 map機能は、これを行うために既に組み込まれています。 Pythonのnext関数と複数行のitertools.isliceを使用して1行を取得できます。あなたのクラスは既に実装されているものの周りの薄いラッパーにすぎないので、ネイティブツールを使用して、自分のクラスを完全に書くのをスキップしてください。

拳私はテストファイル

>>> with open('test.json', 'w') as fp: 
...  for obj in 'foo', 'bar', 'baz': 
...   fp.write(json.dumps(obj) + '\n') 

を生成...

今私は、行の行またはリストを取得するために使用することができますイテレータを作成することができます。 cpythonでは、ファイルをmap関数で安全に開くことができますが、with節で作業することもできます。私はループ

>>> for obj in map(json.loads, open('test.json')): 
...  print(obj) 
... 
foo 
bar 
baz 

内のオブジェクトのすべてを取得したり、リスト内でそれらのいくつかを置く

>>> list(itertools.islice(json_iter, 2)) 
['foo', 'bar'] 

または組み合わせて操作することができます

>>> json_iter = map(json.loads, open('test.json')) 
>>> next(json_iter) 
'foo' 
>>> 
>>> with open('test.json') as fp: 
>>>  json_iter = map(json.loads, open('test.json')) 
>>>  next(json_iter) 
'foo' 

>>> json_iter = map(json.loads, open('test.json')) 
>>> for obj in json_iter: 
...  if obj == 'foo': 
...   list(itertools.islice(json_iter,2)) 
... 
['bar', 'baz'] 

ザ・ポイントは、簡易mapベース新しいユースケースを考えるたびにラッパークラスを更新することなく、イテレーターは必要な作業を行うことができます。

+0

私はこれを手伝ってくれてありがとう!私は地図機能が素晴らしいと思うし、それについて学んだことはうれしいですが、大規模なデータセットで使用するのがよいかどうか疑問です。私たちのJSONファイルは平均して2〜3GBで、各ファイルの1〜1mmの間にあります。これらのファイルのいくつかでマップ機能をテストしている間は、データセット全体を処理することが正しいため、非常に遅いようです。 –

+0

@JoeFusaro - 私はあなたがpython 3.xを使用していると仮定します。そうしないと、爆発してしまいます(2.xでは 'itertools.imap'を使う必要があります)。私が示したように(ファイル上で 'read'や' readlines'のようなことをやっていない)、ファイルから1行を読み込み、その1行を逆直列化して返しますPythonオブジェクト。 jsonオブジェクト自体が大きい場合は、データの断片を読み込み、新しい行をスキャンしたり、新しい行ストリングを作成したり、Pythonオブジェクトにデコードしたりするのに時間がかかります。しかし、一度に1つのjsonオブジェクトしか構築されません。 – tdelaney

+0

ああ、私は2.7を使用しています、私は指定しておくべきです - それについては残念です。 imap関数を試してみましょう。ありがとう! –

関連する問題