辞書型配列したい(std::map
)
1#include "G4SystemOfUnit.hh"
2
3#include <map>
4
5std::map<std::string, G4int> fHitInt{};
6fHitInt["run_id"] = fRunID;
7fHitInt["event_id"] = fEventID;
8fHitInt["track_id"] = fTrackID;
9fHitInt["parent_id"] = fTrackParentID;
10fHitInt["step_id"] = fStepID;
11
12std::map<std::string, G4double> fHitDouble{};
13fHitDouble["energy_deposit"] = fEnergyDeposit / MeV;
14fHitDouble["step_x"] = fStepXYZ.getX() / mm;
15fHitDouble["step_y"] = fStepXYZ.getY() / mm;
16fHitDouble["step_z"] = fStepXYZ.getZ() / mm;
17
18std::map<std::string, G4String> fHitString{};
19fHitString["material_name"] = fMaterialName;
std::map
で辞書型の配列を定義できます。
上のサンプルは、G4VHit
(を継承してユーザが定義したクラス)のヒット情報を、
カラム名と一緒にまとめるために使った例です。
後述のLTSV形式の文字列を生成するために使ってみました。
LTSV形式したい
LTSV形式は、Labeled Tab-Separated Value の略で、 以下のような構造を持つ形式です。
key1:value key2:value key3:value ...
key1:value key2:value key3:value ...
key1:value key2:value key3:value ...
...
あまりメジャーではない形式かもしれませんが、 それぞれの値がラベル名(=カラム名)を持つのが特徴です。 解析するときにカラム名を別途調べる必要がないため、かなり便利です。
また、データの数を追加/削除したときにも、解析ツールの修正をあまりしなくてすみます。 そもそも、データ自身がカラム名を持っているので、特定の解析ツールへの依存性がないのも利点です。
注釈
LTSV形式は、Apacheのログ解析の方法を調べているときに知りました。 デフォルト形式(common形式 もしくは combined形式)のApacheログをパースするのは大変です。 LTSV形式を使ったカスタムログにしておくと、
1G4String ToLtsvString()
2{
3 std::stringstream ss;
4 G4bool is_first = true;
5 for (const auto& pair: fHitInt) {
6 if (!is_first) {
7 ss << ",";
8 };
9 ss << pair.first << ":" << pair.second;
10 is_first = false;
11 };
12 for (const auto& pair: fHitInt) {
13 ss << "," << pair.first << ":" << pair.second;
14 };
15 for (const auto& pair: fHitInt) {
16 ss << "," << pair.first << ":" << pair.second;
17 };
18 G4String ltsv{ss.str()};
19 return ltsv;
20};
このサンプルでは、Tab-Separatedではなく、Comma-SeparatedとしたLTSV亜種を作成しています。 CSV形式にしておくと Excelなどの表計算ソフトでファイルを開いたり、 Pythonで読み込むときの区切り文字(delimiter)もデフォルトのままでよかったり、 と便利だと思うからです。
key1:value, key2:value, key3:value, ...
key1:value, key2:value, key3:value, ...
key1:value, key2:value, key3:value, ...
...
行頭と行末に,
は不要なのでis_first
変数をつかって調整しています。
LTSV形式を読み込みたい
1import csv
2from pathlib import Path
3
4import pandas as pd
5
6def ltsv2data(fname: Path)
7 rows = []
8 with fname.open("r") as f:
9 reader = csv.reader(f)
10 for line in reader:
11 row = dict(field.split(":", 1) for field in line)
12 rows.append(row)
13 data = pd.DataFrame(rows)
14 return data
15
16fname = Path("LTSV形式のファイル.csv")
17data = ltsv2data(fname);
作成したLTSV形式のファイルをPythonのCSVモジュールで読み込み、 pandas.DataFrameに変換する関数を置いておきます。