要は、SQLの結果とかでよくあるこういう整ったレポートを作るには。という話です。
EMPNO ENAME JOB MGR HIREDATE SAL COMM DEPTNO ------ -------- ---------- ---------- -------- ---------- ---------- ---------- 7369 SMITH CLERK 7902 80-12-17 800 20 7499 ALLEN SALESMAN 7698 81-02-20 1600 300 30 7521 WARD SALESMAN 7698 81-02-22 1250 500 30 7566 JONES MANAGER 7839 81-04-02 2975 20 :
必要な情報
整ったレポートを作るには、各列の文字列最大長が必要になります。最大長さえ手に入れば、Pythonにはljust
やrjust
があるので容易に整えることができます。
配列の最大長
配列内の最大長を得るには各要素のlen
を取ってmax
を使えば良いです。ただ、int等の場合も考慮するとstr()
で文字列にしてからlen
を取るといいでしょう。このようなケースではリスト内包式を使うと楽です。
data = ["SMITH", "ALLEN", "WORD"] max([len(str(x)) for x in data]) # --> SMITH,ALLENの5が戻る
最大長が取得できました。
対象のデータ型
SQLの結果のような形式の場合、大抵は以下のようなlist[dict]
の形式になっていると思います。
[ { "empno": "7369", "ename": "SMITH", "job": "CLERK", "mgr": "7902", "hiredate": "1980-12-17T00:00:00.000Z", "sal": "800.00", "comm": null, "deptno": "20" }, { "empno": "7499", "ename": "ALLEN", "job": "SALESMAN", "mgr": "7698", "hiredate": "1981-02-20T00:00:00.000Z", "sal": "1600.00", "comm": "300.00", "deptno": "30" } ]
そのため、任意の列の最大長を取れるように以下のような関数があると便利だと思います。
def get_max_str_length(raw_list_dict_data, column_name): """ 指定したlist[dict]について指定した各列を取得し、その列の最大長を戻す :param list[dict] raw_list_dict_data: :param str column_name: :return: """ max_length = max([len(str(dict_[column_name])) for dict_ in raw_list_dict_data]) # カラム名も結局ヘッダに使うのでそちらのほうが長いかもチェック if len(column_name) > max_length: return len(column_name) return max_length
あとは、この結果を元にrjust
やljust
をする関数を書けば良いです。
def get_pretty_report(base_data, columns): """ インデント等がきれいに揃った形で結果を戻す :param list[dict] base_data: 元データ :param list[str] columns: 元データのうち表示する列のリスト :return: """ ret_str = "" # 各列の最大長のDictを作る max_length_dict = {x: get_max_str_length(base_data, x) for x in columns} # まずはヘッダーを作る header_str = " ".join([x.rjust(max_length_dict[x]) for x in columns]) # ヘッダーの下の---- --- みたいなところを作る header_line = " ".join(["-".rjust(max_length_dict[x], "-") for x in columns]) ret_str += "{}\n".format(header_str) ret_str += "{}\n".format(header_line) # データ部分を追加していく for row_data in base_data: row_data_list = [] for col in columns: col_data = row_data[col] # 文字列でない場合はstr()でキャストする if hasattr(col_data, "rjust"): if col_data: row_data_list.append(col_data.rjust(max_length_dict[col])) else: # Noneは0にしてしまう if col_data: row_data_list.append(str(col_data).rjust(max_length_dict[col])) else: row_data_list.append(str(0).rjust(max_length_dict[col])) # 1行分の組み立て ret_str += "{}\n".format(" ".join(row_data_list)) return ret_str
これはwsgi_lineprof_reporterで使ったコードを元にしています。これくらい汎化しておけば、元データと列を書き換えるだけで整ったレポートが作れるので、SQLの結果を受けている場合などに便利だと思います。