2016-10-07 3 views
0

혼합 유형, 목록 및 사전의 중첩 된 json 개체를 병합하기 위해 재귀 생성기 함수를 작성하려고합니다. 나는 내 자신의 학습을 위해 이것을 부분적으로하고 있기 때문에 인터넷에서 어떤 일이 벌어지고 있는지 더 잘 이해할 수 있도록 예제를 포착하는 것을 피할 수는있다.하지만 막연한 결과를 낳았다. 고리.재귀 생성기 함수 Python 중첩 JSON 데이터

생성기 함수에 전달 된 데이터 원본은 mongo 컬렉션을 반복하는 외부 루프의 출력입니다.

Yield 문과 같은 위치에서 print 문을 사용했을 때 기대했던 결과를 얻었지만 yield 문으로 전환하면 생성자가 외부 루프의 반복마다 하나의 항목 만 생성하는 것처럼 보입니다.

내가 잘못 가고있는 곳을 누군가가 나에게 보여줄 수 있기를 바랍니다.

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

디버깅 할 때 두 버전의 주요 차이점은이 코드 섹션에 도달했을 때의 것입니다. 내가 항복 버전을 테스트입니다 경우

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

dic_recurse(l, fields, counter, '') 라인에 대한 호출의 히트 얻을하지만 내가 함수의 개막식에서 설정 한 인쇄 문은 충돌하지 않기 때문에 함수를 호출하지 않는 것,하지만 경우 코드가 동일한 섹션에 도달하면 함수를 호출하고 전체 함수를 통해 다시 실행됩니다.

아마 발전기와 yield 문 사용에 대한 근본적인 오해가있을 것입니다.

답변

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