inohilog

/var/log/inohiro.log

パフォーマンス

課題で書いたコード。
形態素解析の結果が1行ずつ書いてあるテキストファイルを読んで、頻出頻度を計算するコード。友達のアドバイスもあって、大学の計算機のTerminal.appでパイプでいろいろ処理をつなげれば1行だけでできるのはわかったいたのですが、書き始めたらすぐ書けたので。

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

using System.IO;

namespace nlp_report1
{
	class Program
	{
		static void Main( string[] args )
		{
			using( StreamReader reader = new StreamReader( @"C:\Users\inohiro\Documents\Visual Studio 2008\Projects\nlp_report1\nlp_report1\bin\Debug\result_179k_utf8.txt" ) )
			{
				Dictionary<string, int> collection = new Dictionary<string, int>();

				while( !reader.EndOfStream )
				{
					string tmp = reader.ReadLine();
					if( !collection.ContainsKey( tmp ) )
					{
						collection.Add( tmp, 1 );
					}
					else
					{
						collection[tmp]++;

//	この書き方はやばかった(計算コスト的な意味で)						
//						int val = collection.Where( el => el.Key == tmp ).Select( el => el.Value ).First();
//						collection.Remove( tmp );
//						collection.Add( tmp, ++val );
					}
				}

				var col = collection.OrderByDescending( el => el.Value );

				int i = 0;
				foreach( var el in col )
				{ 
					if( i < 20 )
						Console.WriteLine( string.Format( "{0} : {1}", el.Key, el.Value ) );
					i++;
				}
			}

			Console.ReadKey();
		}
	}
}

実行結果

の, 助詞 : 223053
、, 記号 : 207508
EOS : 178744
。, 記号 : 166468
に, 助詞 : 142045
は, 助詞 : 140306
を, 助詞 : 133726
が, 助詞 : 114142
た, 助動詞 : 111414
する, 動詞 : 103410
て, 助詞 : 94231
だ, 助動詞 : 86917
と, 助詞 : 65979
で, 助詞 : 56523
いる, 動詞 : 51375
も, 助詞 : 40163
れる, 動詞 : 31339
0, 名詞 : 27760
ない, 助動詞 : 27473
1, 名詞 : 24748

反省

なんかうまい書き方ないかなぁと思いつつ、コメントアウトしたようなコードを書いて実行したところ、20分くらい処理し続けてたんじゃないかな。元のテキストファイルが42Mくらいあるのも原因か?と考えたがさすがに時間がかかりすぎ。
「もっと良い書き方があるはず」と考えたところ*1、あれ配列のようにアクセスできるんじゃないかな(ASP.NETのViewStateもDictionaryじゃなかったかな)と思ったので、書き直した。実行して4秒ぐらいで結果が返ってきました。
完全にLINQ脳になってますね。気をつけないと。
また、途中ブレークポイントで処理を止めてみたら、5万ペアくらいつくってました。

*1:そもそも最初は「一度バリューをセットした後に変更できないのはおかしい」、「Dictionaryのメソッドで引数にキーを渡して、バリューをいじる的なメソッドがないかなぁ」と探したんですが、見つからなかったんですよ(まあね)。