目的:C# dictionary関数を使い、Keyが重複している件数をカウントする。
例えば、個人情報4000件とそれぞれの飼い犬/猫の種類が記載されているcsvファイルがあり、このうち、犬の各犬種の割合、猫の各猫種の割合が欲しい。
犬1000件のうちコーギーは200、柴犬500、チワワ300、
猫3000件のうちアメショは1200、ベンガルは800、ペルシャは1000、
のような出力情報が欲しい。
現在dictionaryのKey[0]にそれぞれの種類の値が入っているが、
foreachで各種類をカウントする際の下記の処理の記述に苦戦しています。
-初見の種類には0を入れ、既出の種類には++する。
-最終的に種類ごとにカウントした数を出力する。
素人質問で恐縮ですが、ご回答をお願いいたします。
追記
code
C#
1using 省略 2 3namespace 読み込み 4{ 5 class Program 6 { 7 static void Main(string[] args) 8 { 9 10 var inputFile = @"C:\CSVファイル.txt"; 11 List<string> list = null; 12 Dictionary<string, int> summry = null; 13 14 int DOG9 = 0; 15 int CAT9 = 0; 16 int Total9 = 0; 17 int DOG8 = 0; 18 int CAT8 = 0; 19 int Total8 = 0; 20 int DOG7 = 0; 21 int CAT7 = 0; 22 int Total7 = 0; 23 24 foreach (var line in File.ReadAllLines(inputFile)) 25 { 26 //Dictionaryに入れる 27 if (summry == null) 28 { 29 summry = new Dictionary<string, int>(); 30 continue; 31 } 32 33 //リストにも入れる 34 if (list == null) 35 { 36 list = new List<string>(); 37 continue; 38 } 39 40 41 var clos = line.Split('\t'); 42 string xxx= clos[0]; 43 string xxxx = clos[1]; 44 string xxx = clos[2]; 45 string time = clos[3]; 46 string xxx = clos[4]; 47 string type = clos[5]; 48 string name = clos[6]; ★このカラムの重複数をカウントしたい 49 string xx = $"{xxx} {xxxx}"; 50 51 string MM = Time.Substring(6,1); 52 //Timeの文字列から何月分のデータかを判断する 53 //月ごとに集計が必要 54 55 switch (MM) 56 { 57 //9月分の集計 58 case "9": 59 if (0 <= xxx.IndexOf("DOG")) 60 { 61 DOG9++; 62 //アプリのバージョンを集計する 63 //バージョンが既出でない場合は0を入れて 64 if (summry.ContainsKey(name) == false) 65 { 66 summry.Add(name, 0); 67 } 68 //summry[0]にnameが入っている状態 69 //summry[0]に対して各変数を自動で割り当ててカウントしてほしい 70 71 //なんらかのカウント処理 72 73 } 74 75 else if (0 <= Type.IndexOf("iOS")) 76 { 77 CAT9++; 78 } 79 Total9++; 80 break; 81 82 //8月分の集計 83 case "8": 84 if (0 <= Type.IndexOf("DOG")) 85 { 86 DOG8++; 87 } 88 else if (0 <= Type.IndexOf("iOS")) 89 { 90 CAT8++; 91 } 92 Total8++; 93 break; 94 95 //7月分の集計 96 case "7": 97 if (0 <= Type.IndexOf("DOG")) 98 { 99 DOG7++; 100 } 101 else if (0 <= Type.IndexOf("iOS")) 102 { 103 CAT7++; 104 } 105 Total7++; 106 break; 107 } 108 } 109 110 //月ごとに総数は出力できるようになったがこれはSwitchで分岐したためで 111 //nameは大量の種類があるので自動で初見と既出を判断してカウントする文を書く必要がある 112 System.Console.WriteLine("9月"); 113 System.Console.WriteLine("CAT=" + CAT9); 114 System.Console.WriteLine("DOG=" + DOG9); 115 System.Console.WriteLine("Total=" + Total9 + Environment.NewLine); 116 117 System.Console.WriteLine("8月"); 118 System.Console.WriteLine("CAT=" + CAT8); 119 System.Console.WriteLine("DOG=" + DOG8); 120 System.Console.WriteLine("Total=" + Total8 + Environment.NewLine); 121 122 System.Console.WriteLine("7月"); 123 System.Console.WriteLine("CAT=" + CAT7); 124 System.Console.WriteLine("DOG=" + DOG7); 125 System.Console.WriteLine("Total=" + Total7); 126 127 summry.ToString(); 128 } 129 } 130}
dictionary関数ってなんですか?
情報として、個人情報、犬or猫、犬(猫)の種類の3つがどのように格納されているのか。
(CSVとかそういう話ではなく、コード上での話です。例えばこのような構造体に入っていて、それを配列として持っている等)
現状はどこまで出来ているのか等が分かるようにコードを記載してください。
また、「初見の種類には0を入れ」とありますが、1ではないのですか?
Dictionary<string, int>のようなものです。関数という言い方は正しくないかもしれません。
Dictionary<K, V>クラスでは「重複するKey」というのを認めていませんので、質問の前提条件が成立しないため、回答できません。
既に指摘されていますが、いまどのような実装をしようとしているのか、コードを提示してください。
@YAmaGNZ
static void Main(string[] args)
{
var inputFile = @"C:ディレクトパス\CSVファイル.txt";
List<string> list = null;
Dictionary<string, int> summry = null;
foreach (var line in File.ReadAllLines(inputFile))
{
if (summry == null)
{
summry = new Dictionary<string, int>();
continue;
}
var clos = line.Split('\t');
string Type = clos[0];
string Name = clos[1];
コード上では上記の格納状態になっています。
質問本文は編集できますので、そちらに記載してください。
また、記載されたコードですと中途半端な部分で切れていて、情報がDictionaryには格納されているように見えません。
コードを見る限りCSVを読み込む部分をしっかり作る必要がありそうです。
Dictionaryのインスタンスをループ内で生成する意味とは…。
初見の値に入れるのは1です、これは修正しておきます
こんなコードにしなくてもCSVの中身を展開したリストを生成してLINQ使えばやりたいことは簡単にできます。
LINQを学習してみてください。
DictionaryやKeyを使用することは必須ではなく、
大量のテキストデータのカラムから重複している文字列ごとに件数を集計することが主目的です。
手段が間違っているようであれば集計部分の処理は別の関数を考えますが、二次元配列のデータを効率的に集計する方法としてdictionaryが最も合っていると考えて使用しています。
いや最も適しているのがそれじゃないからコメントしてるんだけど。
学習する意欲がないなら何言っても無駄なんで別にいいですが。
summry["チワワ"]++;
でチワワが増えます。
が、1件のデータをクラスや構造体に格納し、それをListなりに格納した後LINQを使用するとかして集計したほうがいいと思われます。
まず、File.ReadAllLines() ですが、これはメモリにファイルすべてを読み込むので、巨大なファイルだとメモリを圧迫します。特別な理由がないのであれば File.ReadLines() を使いましょう。これだと行ごとに処理できるのでメモリに優しいです。
グループ毎の集計ですが、GroupBy を使うのが定石です。犬種をキーにすれば、犬種ごとにデータをまとめることができます。
https://docs.microsoft.com/ja-jp/dotnet/api/system.linq.enumerable.groupby?view=netcore-3.1
まとめた結果は IGrouping<TKey, TElement> になります。
https://docs.microsoft.com/ja-jp/dotnet/api/system.linq.igrouping-2?view=netcore-3.1
まとめたものは ToDictionary で辞書にしましょう。
https://docs.microsoft.com/ja-jp/dotnet/api/system.linq.enumerable.todictionary?view=netcore-3.1
File
.ReadLines(...)
.Select(a => a.Split("\t"))
.GroupBy(a => a[6])
.ToDictionary(a => a.Key, a => a.Count());
これで集計終わりです。調べてみてください。
本筋には関係ないですが『Dictionary<string, int>のようなもの』はジェネリッククラスと呼びます。ジェネリッククラスはクラスの一種なので単に"Dictionaryクラス"と呼ぶのが普通です。
回答1件
あなたの回答
tips
プレビュー