LoginSignup
0
2

More than 3 years have passed since last update.

スペースでインデントされた文字列をDataFrameとDictionaryに変換

Last updated at Posted at 2019-09-08

開発環境

Windows 10
Python 3.7.3
※ pandasモジュール使用

開発/投稿の動機

コマンドの出力結果をパースして分析するために開発、メモを兼ねて投稿

変換対象文字列

sample_output.py
output = '''aaa
bbb
    ccc
    ddd
        eee
        fff
            gggg
        hhh
            iii
                jjj'''

データ構造に関する変数を定義

setting.py
# インデント単位を定義
indent_num = 4
# 階層数を定義
max_depth = int(max([i.count(' ') for i in output_list]) / indent_num)

StringからDataFrameへ加工

str_to_df.py
import pandas as pd

output_df = pd.DataFrame(index=[],columns=range(max_depth + 1))
for i in range(len(output_list)):
    if output_list[i].count(' ') == 0:
        # 最深までの足りない要素をNone埋めして挿入
        temp_row = [output_list[i]]
        temp_row.extend([None] * (max_depth)) # max_depth - すでに挿入した要素数(1) + depthが0から始まるため1を足す をプラスマイマスゼロのため省略
        output_df = output_df.append(pd.Series(temp_row, index=output_df.columns), ignore_index=True)
        outer_row = [output_list[i]]
        depth = 0
    else:
        # 1つ前のレコードよりも1階層深かったら"depth"を進める
        if output_list[i].count(' ') == (depth + 1) * indent_num:
            depth += 1
        # 挿入用のリストを作成
        temp_row = outer_row.copy()
        temp_row.append(output_list[i].strip(' '))
        list_length = len(temp_row)
        # 最深よりも浅いレコードはNone埋めして挿入
        if list_length < max_depth + 1:
            temp_row.extend([None] * (max_depth - list_length + 1))
            output_df = output_df.append(pd.Series(temp_row, index=output_df.columns), ignore_index=True)
        # 最深のレコードはそのまま挿入
        else:
            output_df = output_df.append(pd.Series(temp_row, index=output_df.columns), ignore_index=True)
        # 次のレコードが1階層深かったらouter_rowを挿入したレコード(Noneは除去)と置き換える
        if i + 1 < len(output_list):
            if output_list[i + 1].count(' ') == (depth + 1) * indent_num:
                outer_row = [x for x in temp_row if x]

DataFrameからDictionaryへ加工

df_to_dict.py
output_dict = {}
for i in sorted(output_df.keys())[:-1]:
    for j in [x for x in output_df[i].drop_duplicates() if x]:   
        if i == 0:
            # 配下の要素が無かったら外側の辞書定義のみ
            if len([x for x in output_df[output_df[i] == j][i + 1] if x]) == 0:
                output_dict[j] = None
            else:
                output_dict[j] = {}
                filtered_dict = output_dict[j]
        else:
            # 配下の要素が無かったら自分だけ追加
            if len([x for x in output_df[output_df[i] == j][i + 1] if x]) == 0:
                if (j not in filtered_dict) & (i != max_depth - 1):
                    filtered_dict[j] = None
            # 配下の要素があったら辞書を作って埋める
            elif i != max_depth - 1:
                filtered_dict[j] = {}
                temp_dict = {}
                # 配下のキーをループ処理
                for key in [x for x in output_df[output_df[i] == j][i + 1].drop_duplicates() if x]:
                    # すでにキーがあったら更新
                    if key in temp_dict.keys():
                        temp_dict.update({key:[x for x in list(output_df[output_df[max_depth - 1] == key][max_depth]) if x]})
                    # 無かったら追加
                    else:
                        temp_dict[key] = [x for x in list(output_df[output_df[max_depth - 1] == key][max_depth]) if x]
                # 作成した辞書を挿入
                filtered_dict[j] = temp_dict
あとがき

求める出力を得られるようになったため当面このまま使うが、不要なロジックの精査を要する。

0
2
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
2