前提・実現したいこと
yield returnされたクラス情報を基に、一つの辞書を作りたいです。
仕様としては以下の通りです。
仕様
- 情報を呼び出すクラス
Program
と呼ばれるクラスAnother
がいる。 Anotherクラス
Humanクラス
: 国名、名前、ログイン回数をプロパティに持つ。GetHumansメソッド
: (出来ればプロパティにしたい)情報を順に取り出す。Programクラス
- GetHumans~~の中で、~~から国名、名前、ログイン回数の多段辞書を作る。(Jsonとして外に出す情報)
** 国名、名前が等しい場合、ログイン回数は加算する。**
発生している問題
Anotherクラス
側で辞書を持たずにIEnumerable<Human>で順次出力させるような仕様としたのですが、
その情報を辞書化するにあたっての処理が泥臭いと感じています。
(国名があれば名前をチェックし、存在すれば+=、そうでなければ辞書をAddする)
開発環境
OS: Windows10
.NET Core ランタイムのバージョン: .NET SDK (5.0.100) // 3.1でもよい。
最近新規作成したプロジェクトなので、バージョンの制約はないです。
得られる辞書情報
Json
1{ 2 "JP": { 3 "Taro": 11, 4 "Jiro": 5 5 }, 6 "US": { 7 "Mike": 20 8 } 9}
得たい辞書情報
Json
1[ 2 { 3 "Country": "JP", 4 "PersonalData": [ 5 { 6 "Name": "Taro", 7 "Login": 11 8 }, 9 { 10 "Name": "Jiro", 11 "Login": 5 12 } 13 ] 14 }, 15 { 16 "Country": "US", 17 "PersonalData": [ 18 { 19 "Name": "Mike", 20 "Login": 20 21 } 22 ] 23 } 24]
該当のソースコード(元コード)
C#
1using System; 2using System.Collections.Generic; 3 4namespace test 5{ 6 public class Another 7 { 8 public class Human 9 { 10 public string country { get; set; } 11 public string name { get; set; } 12 public uint login { get; set; } 13 } 14 15 public IEnumerable<Human> GetHumans() 16 { 17 yield return new Human 18 { 19 country = "JP", 20 name = "Taro", 21 login = 10, 22 }; 23 yield return new Human 24 { 25 country = "JP", 26 name = "Jiro", 27 login = 5, 28 }; 29 yield return new Human 30 { 31 country = "US", 32 name = "Mike", 33 login = 20, 34 }; 35 yield return new Human 36 { 37 country = "JP", 38 name = "Taro", 39 login = 1, 40 }; 41 } 42 } 43 44 class Program 45 { 46 static void Main(string[] args) 47 { 48 var another = new Another(); 49 var dict = new Dictionary<string, Dictionary<string, uint>>(); 50 foreach (var human in another.GetHumans()) 51 { 52 if (dict.ContainsKey(human.country)) 53 if (dict[human.country].ContainsKey(human.name)) 54 dict[human.country][human.name] += human.login; 55 else 56 dict[human.country].Add(human.name, human.login); 57 else 58 dict.Add( 59 human.country, new Dictionary<string, uint> 60 { 61 [human.name] = human.login, 62 }); 63 } 64 Console.WriteLine(dict); 65 } 66 } 67}
試したこと
Linqを使って、国ごとのグループを作成することは成功したものの、
最後の
Json
1{ 2 "country": "JP", 3 "name": "Taro", 4 "login": 1 5}
が重複しており仕様が満たせないです。
C#
1var dict2 = another.GetHumans().GroupBy(x => x.country).ToDictionary(x => x.Key);
補足情報
現在試している環境: vscodeでdotnet new console
したものとなっております。
得られた回答から少し修正を加えたもの
グループ化した結果を最終的な出力にもっていくために、grouped
をforeachして
国名のキーチェック、名前のキーチェックをして詰め直す作業をしていますが、
この方法もやはり冗長な気がしていて、Selectで射影する際にToDictionaryできないものかと
試行錯誤をしています。
(.GroupByの後、.Selectして.ToDictinaryする or 単にToDictionaryで結果を得られないだろうか)
C#
1using System; 2using System.Collections.Generic; 3using System.Linq; 4using System.Text.Json; 5 6namespace test 7{ 8 public class Another 9 { 10 public class Human 11 { 12 public string Country { get; set; } 13 public string Name { get; set; } 14 public uint Login { get; set; } 15 } 16 17 public IEnumerable<Human> GetHumans() 18 { 19 yield return new Human 20 { 21 Country = "JP", 22 Name = "Taro", 23 Login = 10, 24 }; 25 yield return new Human 26 { 27 Country = "JP", 28 Name = "Jiro", 29 Login = 5, 30 }; 31 yield return new Human 32 { 33 Country = "US", 34 Name = "Mike", 35 Login = 20, 36 }; 37 yield return new Human 38 { 39 Country = "JP", 40 Name = "Taro", 41 Login = 1, 42 }; 43 } 44 } 45 46 class Program 47 { 48 static void Main(string[] args) 49 { 50 var another = new Another(); 51 var dict = new Dictionary<string, Dictionary<string, uint>>(); 52 foreach (var human in another.GetHumans()) 53 { 54 if (dict.ContainsKey(human.Country)) 55 if (dict[human.Country].ContainsKey(human.Name)) 56 dict[human.Country][human.Name] += human.Login; 57 else 58 dict[human.Country].Add(human.Name, human.Login); 59 else 60 dict.Add( 61 human.Country, new Dictionary<string, uint> 62 { 63 [human.Name] = human.Login, 64 }); 65 } 66 Console.WriteLine(dict); 67 68 var grouped = another.GetHumans() 69 .GroupBy(h => new { Country = h.Country, Name = h.Name }) 70 .Select(g => new Another.Human 71 { 72 Country = g.Key.Country, 73 Name = g.Key.Name, 74 Login = (uint)g.Sum(x => x.Login) 75 }); 76 var json = JsonSerializer.Serialize(grouped); 77 Console.WriteLine(json); 78 79 var dict2 = new Dictionary<string, Dictionary<string, uint>>(); 80 foreach (var item in grouped) 81 if (dict2.ContainsKey(item.Country)) 82 dict2[item.Country].Add(item.Name, item.Login); 83 else 84 dict2.Add( 85 item.Country, new Dictionary<string, uint> 86 { 87 [item.Name] = item.Login, 88 }); 89 var json2 = JsonSerializer.Serialize(dict2); 90 Console.WriteLine(json2); 91 } 92 } 93}
さらに追記
- 辞書は外部にてJsonデータとして使えるようにフィールド名を持つこと。
- AnotherからIEnumerableで1件ずつ来る仕様は変えてはならない。
回答1件
あなたの回答
tips
プレビュー