やりたいこと
やりたいことを表すいい名前が分からなかったので「一つのエンティティを複数のエンティティに分割する」とタイトルに書いてありますが、具体的には下表の"分割前"から"分割後"を作るメソッドを書きたいと思います。
・分割前
ID | Fruit1 | Price1 | Fruit2 | Price2 | Fruit3 | Price3 |
---|---|---|---|---|---|---|
1 | りんご | 150 | ぶんたん | 200 | めろん | 2000 |
2 | みかん | 50 | ぶどう | 300 | なし | 130 |
3 | はっさく | 100 | いちご | 400 | ざくろ | 500 |
・分割後
Sequence | Fruit | Price |
---|---|---|
1 | りんご | 150 |
2 | みかん | 50 |
3 | はっさく | 100 |
4 | ぶんたん | 200 |
5 | ぶどう | 300 |
6 | いちご | 400 |
7 | めろん | 2000 |
8 | なし | 130 |
9 | ざくろ | 500 |
"分割前"表は1行に果物の情報が3つ並んでいます。"分割後"表では1行に一つの果物を持つようになっています。シチュエーションとして、一行に複数項目あるデータでは処理を行いづらくなったためデータの変換をおこなうことを想定しています。
データ構造
C#上でのデータの持ち方ですが、"分割前""分割後"のデータそれぞれは下記クラスをリストで持つようにしています。
// 分割前のデータ1行が入る
public class InputRecord
{
public int ID { get; set; }
public string Fruit1 { get; set; }
public int Price1 { get; set; }
public string Fruit2 { get; set; }
public int Price2 { get; set; }
public string Fruit3 { get; set; }
public int Price3 { get; set; }
}
// 分割後のデータ1行が入る
public class OutputRecord
{
public int Sequence { get; set; }
public string Fruit { get; set; }
public int Price { get; set; }
}
分割を行なうメソッド
private static IEnumerable<OutputRecord> ConvertToOutput(List<InputRecord> input)
{
var seq = 0;
foreach(var record in input)
{
// Fruit1
seq++;
yield return new OutputRecord
{
Sequence = seq,
Fruit = record.Fruit1,
Price = record.Price1,
};
// Fruit2
seq++;
yield return new OutputRecord
{
Sequence = seq,
Fruit = record.Fruit2,
Price = record.Price2,
};
// Fruit3
seq++;
yield return new OutputRecord
{
Sequence = seq,
Fruit = record.Fruit3,
Price = record.Price3,
};
}
}
1行を3分割することを考えるとこのようなメソッドが出来上がります。foreachでループして、一行ごとにyield returnを3回行っているだけですね。
メソッド呼び出し部
static void Main(string[] args)
{
// テストデータ(分割前表と同じ内容)
var input = new List<InputRecord>
{
new InputRecord
{
ID = 1,
Fruit1 = "りんご",
Price1 = 150,
Fruit2 = "みかん",
Price2 = 50,
Fruit3 = "はっさく",
Price3 = 100,
},
new InputRecord
{
ID = 2,
Fruit1 = "ぶんたん",
Price1 = 200,
Fruit2 = "ぶどう",
Price2 = 300,
Fruit3 = "いちご",
Price3 = 400,
},
new InputRecord
{
ID = 3,
Fruit1 = "めろん",
Price1 = 2000,
Fruit2 = "なし",
Price2 = 130,
Fruit3 = "ざくろ",
Price3 = 500,
},
};
// メソッド呼び出し
List<OutputRecord> output = ConvertToOutput(input).ToList();
}
テスト用の入力データ作成とメソッド呼び出しを行なうとこのようになります。
考察
メリット
・List<>クラスのAddメソッドを書かなくてすむ
デメリット
・yield句に慣れていないと処理の流れを見失う