2017-02-22 22 views
0

私はPython辞書のリストを見たいと思っていますが、スプレッドシートのデータをデータ構造に取り込む際に問題があると考えています。私が持っている問題は、1つの行に、親辞書の値と1つの子を移入するデータがある可能性があるということです。後続の行では、親の列の値が空の場合、子の列が前の親に属しているとします。親データが空でない新しい行が発生した場合は、それを新しい親と見なしてリストに追加します。私はこのように見えるようなデータ構造をしたいと思います入れ子になった辞書にスプレッドシートデータを挿入する

+--------------+-------------------+---------+----------+--------------------+--------------+------------------+-------------+---------------+----------------+ 
| name   | descr    | adminSt | authSt | server_hostname_ip | server_descr | server_preferred | server_EPG | server_minPol | server_maxPoll | 
+--------------+-------------------+---------+----------+--------------------+--------------+------------------+-------------+---------------+----------------+ 
| test1-NTPPOL | Test NTP Policy | enabled | disabled | 10.10.10.10  | NTP1 server | yes    | oob-default | 4    | 6    | 
+--------------+-------------------+---------+----------+--------------------+--------------+------------------+-------------+---------------+----------------+ 
|    |     |   |   | 10.10.10.11  | NTP2 server | no    | oob-default | 4    | 6    | 
+--------------+-------------------+---------+----------+--------------------+--------------+------------------+-------------+---------------+----------------+ 
|    |     |   |   | 10.10.10.12  | NTP3 server | no    | oob-default | 4    | 6    | 
+--------------+-------------------+---------+----------+--------------------+--------------+------------------+-------------+---------------+----------------+ 
| test2-NTPPOL | Test 2 NTP policy | enabled | disabled | 20.10.10.10  | NTP1 server | yes    | oob-default | 4    | 6    | 
+--------------+-------------------+---------+----------+--------------------+--------------+------------------+-------------+---------------+----------------+ 
|    |     |   |   | 20.10.10.11  | NTP2 server | no    | oob-default | 4    | 6    | 
+--------------+-------------------+---------+----------+--------------------+--------------+------------------+-------------+---------------+----------------+ 
|    |     |   |   | 20.10.10.12  | NTP3 server | no    | oob-default | 4    | 6    | 
+--------------+-------------------+---------+----------+--------------------+--------------+------------------+-------------+---------------+----------------+ 

これは、スプレッドシートがどのように見えるかの例である

[ 
    { 
    "name": "NTP_Policy1", 
    "descr": "NTP Policy 1", 
    "adminSt": "enabled", 
    "authSt": "disabled", 
    "servers": [ 
     { 
     "hostname": "10.10.10.10", 
     "descr": "NTP1 Server", 
     "preferred": true, 
     "server_EPG": "oob-default", 
     "minPoll": 4, 
     "maxPoll": 6 
     }, 
     { 
     "hostname": "20.10.10.10", 
     "descr": "NTP2 Server", 
     "preferred": false, 
     "server_EPG": "oob-default", 
     "minPoll": 4, 
     "maxPoll": 6 
     } 
    ] 
    }, 
    { 
    "name": "NTP_Policy2", 
    "descr": "NTP Policy 2", 
    "adminSt": "enabled", 
    "authSt": "disabled", 
    "servers": [ 
     { 
     "hostname": "30.10.10.10", 
     "descr": "NTP3 Server", 
     "preferred": true, 
     "server_EPG": "oob-default", 
     "minPoll": 4, 
     "maxPoll": 6 
     }, 
     { 
     "hostname": "40.10.10.10", 
     "descr": "NTP4 Server", 
     "preferred": false, 
     "server_EPG": "oob-default", 
     "minPoll": 4, 
     "maxPoll": 6 
     } 
    ] 
    } 
] 

私はこのように見えて来た最も近いのコードを、その後の行では、子レベルが親レベルに追加されました。

>>> import pyexcel 
>>> from pprint import pprint 
>>> def excel_to_dict(sheet): 
...  rows = sheet.iter_rows() 
...  keys = next(rows) 
...  dict_list = [] 
...  # For each row in the spreadsheet, 
...  # Create an iterator pair so that the key is iterated over at the same time as its matching cell in the row 
...  # Then save that pairing as descriptors of the switch 
...  for row in rows: 
...   dict = {} 
...   dict['servers'] = [] 
...   server_atts = {} 
...   for key,cell in zip(keys, row): 
...    if str(cell.value) != 'None' and str(key.value) == 'name': 
...     dict[str(key.value)] = str(cell.value) 
...     parentKey = str(key.value) 
...    elif (str(cell.value) != 'None' and str(key.value) == 'descr') or (str(cell.value) != 'None' and str(key.value) == 'adminSt') or (str(cell.value) != 'None' and str(key.value) == 'authSt'): 
...     dict[str(key.value)] = str(cell.value) 
...    elif str(cell.value) == 'None': 
...     continue 
...    else: 
...     server_atts[str(key.value)] = str(cell.value) 
...   dict['servers'].append(server_atts.copy()) 
...   dict_list.append(dict.copy()) 
...  return dict_list 
>>> wb = openpyxl.load_workbook('aci_config.xlsx') 
>>> ntpPolsSheet = wb.get_sheet_by_name('ntp_pol') 
>>> ntpPols = excel_to_dict(ntpPolsSheet) 
>>> 
>>> pprint(ntpPols) 
[{'adminSt': 'enabled', 
    'authSt': 'disabled', 
    'descr': 'Test NTP Policy', 
    'name': 'test1-NTPPOL', 
    'servers': [{'server_EPG': 'oob-default', 
       'server_descr': 'NTP1 server', 
       'server_hostname_ip': '10.10.10.10', 
       'server_maxPoll': '6', 
       'server_minPol': '4', 
       'server_preferred': 'yes'}]}, 
{'servers': [{'server_EPG': 'oob-default', 
       'server_descr': 'NTP2 server', 
       'server_hostname_ip': '10.10.10.11', 
       'server_maxPoll': '6', 
       'server_minPol': '4', 
       'server_preferred': 'no'}]}, 
{'servers': [{'server_EPG': 'oob-default', 
       'server_descr': 'NTP3 server', 
       'server_hostname_ip': '10.10.10.12', 
       'server_maxPoll': '6', 
       'server_minPol': '4', 
       'server_preferred': 'no'}]}, 
{'adminSt': 'enabled', 
    'authSt': 'disabled', 
    'descr': 'Test 2 NTP policy', 
    'name': 'test2-NTPPOL', 
    'servers': [{'server_EPG': 'oob-default', 
       'server_descr': 'NTP1 server', 
       'server_hostname_ip': '20.10.10.10', 
       'server_maxPoll': '6', 
       'server_minPol': '4', 
       'server_preferred': 'yes'}]}, 
{'servers': [{'server_EPG': 'oob-default', 
       'server_descr': 'NTP2 server', 
       'server_hostname_ip': '20.10.10.11', 
       'server_maxPoll': '6', 
       'server_minPol': '4', 
       'server_preferred': 'no'}]}, 
{'servers': [{'server_EPG': 'oob-default', 
       'server_descr': 'NTP3 server', 
       'server_hostname_ip': '20.10.10.12', 
       'server_maxPoll': '6', 
       'server_minPol': '4', 
       'server_preferred': 'no'}]}] 

dictリストに正しく入力するにはどのようなコードが必要ですか?データを簡単にインポートできるスプレッドシート形式がありますか?私はこのシートを複数のシートではなく、1つのシートにまとめようとしています。

+1

この目的で 'pandas'を使用できませんか?数行のコードで同じ結果が得られます。 –

+0

あなたは 'json'に変換する必要があります –

+0

あなたは遭遇している問題は何ですか?データは入ってきますが、あなたが期待しているものではありませんか? – aydow

答えて

0

対処が簡単であるため、.xlsxファイルをcsv形式で保存することをお勧めします。これは、テキスト形式で次のようになります。そして、あなたはcsvファイルを読み、JSONに変換するためにパンダを使用することができます

name,descr,adminSt,authSt,server_hostname_ip,server_descr,server_preferred,server_EPG,server_minPoll, 
test1-NTPPOL,Test NTP Policy,enabled,disabled,10.10.10.10,NTP1 server,yes,oob-default,4,6 
,,,,10.10.10.11,NTP2 server,no,oob-default,4,6 
,,,,10.10.10.12,NTP3 server,no,oob-default,4,6 
test2-NTPPOL,Test 2 NTP policy,enabled,disabled,20.10.10.10,NTP1 server,yes,oob-default,4,6 
,,,,20.10.10.11,NTP2 server,no,oob-default,4,6 
,,,,20.10.10.12,NTP3 server,no,oob-default,4,6 

。 Pandasには.ilocという関数があります。この関数では、まず行ごとにインデックスを作成し、次に列名でインデックスを作成することができます。

import pandas as pd 
from beeprint import pp 

def excel_to_dict(sheet): 
    dict_list = [] 
    last_test_dict = None 
    for i in xrange(len(sheet)): 
     # When we find a new row with a name value, we want to insert 
     # the old test_dict into the dict_list and make a new test_dict. 
     # Also, we want to skip the first row to not append an empty dict. 
     if pd.notnull(sheet.iloc[i]['name']): 
      if i != 0: 
       dict_list.append(test_dict) 
      test_dict = {} 
      test_dict['name'] = sheet.iloc[i]['name'] 
      test_dict['descr'] = sheet.iloc[i]['descr'] 
      test_dict['adminSt'] = sheet.iloc[i]['adminSt'] 
      test_dict['authSt'] = sheet.iloc[i]['authSt'] 
      test_dict['servers'] = [] 
      server_info = {} 
      server_info['server_hostname'] = sheet.iloc[i]['server_hostname_ip'] 
      server_info['server_descr'] = sheet.iloc[i]['server_descr'] 
      server_info['server_preferred'] = sheet.iloc[i]['server_preferred'] 
      server_info['server_EPG'] = sheet.iloc[i]['server_EPG'] 
      server_info['minPoll'] = sheet.iloc[i]['server_minPoll'] 
      server_info['maxPoll'] = sheet.iloc[i]['server_maxPoll'] 
      test_dict['servers'].append(server_info) 
      last_test_dict = test_dict # keep a handle to our new dict 
     else: 
      # Use the handle to the last test dict created to add info 
      # about a new server without modifying the name of the test 
      server_info = {} 
      server_info['server_hostname'] = sheet.iloc[i]['server_hostname_ip'] 
      server_info['server_descr'] = sheet.iloc[i]['server_descr'] 
      server_info['server_preferred'] = sheet.iloc[i]['server_preferred'] 
      server_info['server_EPG'] = sheet.iloc[i]['server_EPG'] 
      server_info['minPoll'] = sheet.iloc[i]['server_minPoll'] 
      server_info['maxPoll'] = sheet.iloc[i]['server_maxPoll'] 
      last_test_dict['servers'].append(server_info) 

    # In case we didn't enter the last test dict into the list 
    dict_list.append(last_test_dict) 
    return dict_list 

sheet = pd.read_csv('sheet.csv', sep=',') 
pp(excel_to_dict(sheet)) 
+0

これは完全に機能するようです。私が持っている唯一の質問は 'if i!= 0:then dict_list.append(test_dict)'です。これは、最初の行ではなく空白の名前の行にない限り、test_dictをメイン辞書リストに追加することを意味します。私たちがコードのこの部分を最後に通過したときに、test_dictにあったものを追加していませんか?この後、私たちは期待どおりにラインからデータを取得します。なぜ私たちがインデックス0になくても新しい名前のエントリにtest_dictを追加する必要があるのか​​分かりません。 – mikey

+0

そうですね、始めにそれを持っている点は、新しいテスト名を含む新しい行を処理するたびに、前の 'test_dict'を' dict_list'に追加するようなものです。しかし、行1になると、前の 'test_dict'は空になり、空のdictを' dict_list'にプッシュしようとします。だから私はi == 0でそれをしないようにします。これは、最終的な 'test_dict'がforループの' dict_list'に入れられないので、return文の前に行を追加したことを意味します。 – Chirag

+0

私は今理解しています。この機能を一般化する方法はありますか?私は別のシートを持っていますが、これは、この機能の恩恵を受ける別の列を持っています。ただし、それは難しいレイアウトにコード化されており、すべてのシートごとに違うコードをする必要があります。最後の列から最初のデータ構造を構築するのが最も簡単な方法でしょうか?私はこれらのヘッダーを持つシートを持っているので、私は尋ねます:サイト、建物、床、部屋、行、ラック。サイトには複数の建物を持つ名前があり、建物には名前や複数の階などがあります。 – mikey

関連する問題