2016-10-07 16 views
0

混合型、リスト、辞書の入れ子になったjsonオブジェクトを平坦化するための再帰型ジェネレータ関数を作成しようとしています。私はこれを自分自身の学習のために部分的にやっているので、インターネットからの例をとらえて、何が起こっているのかをよりよく理解するために避けていますが、挫折しました。ループ。再帰関数ジェネレータ関数Python入れ子JSONデータ

ジェネレータ関数に渡されるデータのソースは、mongoコレクションを反復している外側ループの出力です。

私はYieldステートメントと同じ場所でprintステートメントを使用しましたが、期待していた結果が得られましたが、yieldステートメントに切り替えると、外部ループの反復ごとに1つのアイテムしか生成されないようです。

私が間違っている場所を誰かに教えてください。

columns = ['_id' 
    , 'name' 
    , 'personId' 
    , 'status' 
    , 'explorerProgress' 
    , 'isSelectedForReview' 
      ] 
db = MongoClient().abcDatabase 

coll = db.abcCollection 


def dic_recurse(data, fields, counter, source_field): 
    counter += 1 
    if isinstance(data, dict): 
     for k, v in data.items(): 
      if k in fields and isinstance(v, list) is False and isinstance(v, dict) is False: 
       # print "{0}{1}".format(source_field, k)[1:], v 
       yield "{0}{1}".format(source_field, k)[1:], v 
      elif isinstance(v, list): 
       source_field += "_{0}".format(k) 
       [dic_recurse(l, fields, counter, source_field) for l in data.get(k)] 
      elif isinstance(v, dict): 
       source_field += "_{0}".format(k) 
       dic_recurse(v, fields, counter, source_field) 
    elif isinstance(data, list): 
     [dic_recurse(l, fields, counter, '') for l in data] 


for item in coll.find(): 
    for d in dic_recurse(item, columns, 0, ''): 
     print d 

以下は反復処理中のデータのサンプルですが、ネストは表示されているものを超えて増加します。

{ 
    "_id" : ObjectId("5478464ee4b0a44213e36eb0"), 
    "consultationId" : "54784388e4b0a44213e36d5f", 
    "modules" : [ 
     { 
      "_id" : "FF", 
      "name" : "Foundations", 
      "strategyHeaders" : [ 
       { 
        "_id" : "FF_Money", 
        "description" : "Let's see where you're spending your money.", 
        "name" : "Managing money day to day", 
        "statuses" : [ 
         { 
          "pid" : "54784388e4b0a44213e36d5d", 
          "status" : "selected", 
          "whenUpdated" : NumberLong(1425017616062) 
         }, 
         { 
          "pid" : "54783da8e4b09cf5d82d4e11", 
          "status" : "selected", 
          "whenUpdated" : NumberLong(1425017616062) 
         } 
        ], 
        "strategies" : [ 
         { 
          "_id" : "FF_Money_CF", 
          "description" : "This option helps you get a picture of how much you're spending", 
          "name" : "Your spending and savings.", 
          "relatedGoals" : [ 
           { 
            "_id" : ObjectId("54784581e4b0a44213e36e2f") 
           }, 
           { 
            "_id" : ObjectId("5478458ee4b0a44213e36e33") 
           }, 
           { 
            "_id" : ObjectId("547845a5e4b0a44213e36e37") 
           }, 
           { 
            "_id" : ObjectId("54784577e4b0a44213e36e2b") 
           }, 
           { 
            "_id" : ObjectId("5478456ee4b0a44213e36e27") 
           } 
          ], 
          "soaTrashWarning" : "Understanding what you are spending and saving is crucial to helping you achieve your goals. Without this in place, you may be spending more than you can afford. ", 
          "statuses" : [ 
           { 
            "personId" : "54784388e4b0a44213e36d5d", 
            "status" : "selected", 
            "whenUpdated" : NumberLong(1425017616062) 
           }, 
           { 
            "personId" : "54783da8e4b09cf5d82d4e11", 
            "status" : "selected", 
            "whenUpdated" : NumberLong(1425017616062) 
           } 
          ], 
          "trashWarning" : "This option helps you get a picture of how much you're spending and how much you could save.\nAre you sure you don't want to take up this option now?\n\n", 
          "weight" : NumberInt(1) 
         }, 

更新 私は、彼らが本当に何を変更したと私は、デバッガで行ずつステップスルーしてきたことはよく分からないが、私は、発電機の機能にいくつかの変更を加えました印刷バージョンと利回りバージョンの両方。新しいコードは以下の通りです。

def dic_recurse(data, fields, counter, source_field): 
    print 'Called' 
    if isinstance(data, dict): 
     for k, v in data.items(): 
      if isinstance(v, list): 
       source_field += "_{0}".format(k) 
       [dic_recurse(l, fields, counter, source_field) for l in v] 
      elif isinstance(v, dict): 
       source_field += "_{0}".format(k) 
       dic_recurse(v, fields, counter, source_field) 
      elif k in fields and isinstance(v, list) is False and isinstance(v, dict) is False: 
       counter += 1 
       yield "L{0}_{1}_{2}".format(counter, source_field, k.replace('_', ''))[1:], v 
    elif isinstance(data, list): 
     for l in data: 
      dic_recurse(l, fields, counter, '') 

デバッグ時の2つのバージョンの主な違いは、このセクションにヒットした場合のようです。

elif isinstance(data, list): 
      for l in data: 
       dic_recurse(l, fields, counter, '') 

私はdic_recurse(l, fields, counter, '')ラインへの呼び出しのが打撃を受ける降伏バージョンをテストしていますが、私は、関数の開口部に設定された任意のprint文がヒットされていないので、関数を呼び出すように見えるが、そうでない場合はない場合私はprintを使って同じことをします。コードが同じセクションにヒットすると、関数をうかがって呼び出し、関数全体を実行します。

私はおそらく、発電機と歩留まり声明の使用に関する基本的なことを誤解していると確信しています。

答えて

0

これに対する応答の代わりに、他の誰にとっても有用であると判明した場合に備えて、最新の解決策を投稿したかっただけです。

yield関数を追加する必要がありますので、ジェネレータ関数の各再帰呼び出しの結果を次の関数で使用するために渡すことができます。訂正して幸いです。

def dic_recurse(data, fields, counter, source_field): 
    if isinstance(data, dict): 
     counter += 1 
     for k, v in data.items(): 
      if isinstance(v, list): 
       for field_data in v: 
        for list_field in dic_recurse(field_data, fields, counter, source_field): 
         yield list_field 
      elif isinstance(v, dict): 
       for dic_field in dic_recurse(v, fields, counter, source_field): 
        yield dic_field 
      elif k in fields and isinstance(v, list) is False and isinstance(v, dict) is False: 
       yield counter, {"{0}_L{1}".format(k, counter): v} 
    elif isinstance(data, list): 
     counter += 1 
     for list_item in data: 
      for li2 in dic_recurse(list_item, fields, counter, ''): 
       yield li2