質問するログイン新規登録
C#

C#はマルチパラダイムプログラミング言語の1つで、命令形・宣言型・関数型・ジェネリック型・コンポーネント指向・オブジェクティブ指向のプログラミング開発すべてに対応しています。

Q&A

解決済

1回答

18065閲覧

C#のfor(each)ループの速度が遅い?

kurosuke___

総合スコア217

C#

C#はマルチパラダイムプログラミング言語の1つで、命令形・宣言型・関数型・ジェネリック型・コンポーネント指向・オブジェクティブ指向のプログラミング開発すべてに対応しています。

0グッド

0クリップ

投稿2016/07/28 06:06

0

0

こんにちは。

現在約1200回のforループ、その中のforで約160000回のforループで処理をするプログラムを書いたのですが、終了までにかなり時間がかかります。

C#

1string tempString = ""; 2 3foreach (string[] x in senNihyaku) 4{ 5 foreach (string[] y in juRokuan) 6 { 7 cat = // y[1]は住所なので、それを渡すと〇〇県と〇〇市にわけられた配列を返す関数呼び出し 8 if (x.Contains(cat[1])){ tempString += y[2]} 9 } 10}

上記のような感じです。
都道府県市区町村を分ける関数に関しては、事前に〇〇県〇〇市のような文字列が入っている配列を用意しておき、それをループで回して、引数で渡された住所と照らしあわせて、見つかった場合はその文字列を返すというような関数です。

160000回のループは約2分30秒かかります。
なので約50時間もかかってしまう計算になります。

C#のループというのは、こレくらいの速度が普通なんでしょうか?

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

guest

回答1

0

ベストアンサー

こんにちは。

恐らくfor文の処理が遅いのではなく、ループの中身の処理に時間がかかっているということではないでしょうか?
150秒/160,000回=1mSec弱ですので、処理の内容によっては十分にありえる数字と思います。
文字列分解、文字列検索、文字列追加はそれぞれそこそこ重めの処理です。

試しにループの中に何もしない関数を1つ呼び出すだけにして時間を測ってみてはどうでしょうか?
やったことはないですが、160,000回のループに1秒も掛からないのではないかと思います。


【追加】
そのようなケースで速いアルゴリズムを考えるのがプログラマの醍醐味かも。
例えば、16万個の住所を単純にソートしておいて、渡された住所に最も近いものを2分探索等で検索し、最も近いもの2つについて分解と厳密なマッチを行うことで、かなり高速化できるだろうと思います。

住所表記に揺れ(例えば、間にスペースが入っていたり、県名があったりなかったり、同じ市なのに旧名と新名が入り混じっているなど)があるとうまく行かないので、事前に正規化しておくこと等が必要になります。

投稿2016/07/28 06:16

編集2016/07/28 06:23
Chironian

総合スコア23274

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

kurosuke___

2016/07/28 06:33

迅速な回答有り難うございます。 都道府県市町村区を分離する関数の速度を測ったところ、約0.001秒かかってました。ループ一回分にかかる時間の99%はこの処理みたいですね。 主にSubstringをつかって分離していますが、これが遅いんでしょうか・・・
kurosuke___

2016/07/28 06:43

なるほど・・・2分探索というものの存在自体知りませんでした。 ちらっと調べてみましたが、とても難しそう?なので、勉強しながら、Chironianさんのおっしゃっている方法を実装してみたいと思います。ありがとうございました。
Chironian

2016/07/28 06:46

あ、「都道府県」、「市」、「町」、「村」、「区」に分解しているのですか? 更に表記の揺れ等も吸収しているような処理でしたら、1mSecもありえそうな気がします。 どうしても分解が必要でしたら、メモリを多く使いますが、16万件のデータを事前に分解しておいて検索すれば50時間の処理に対して大凡99%の高速化が可能ですね。 1件当たり100バイトとしても16万件で16MBytesですから、今のPCなら使っても問題ないと思いますよ。
kurosuke___

2016/07/28 07:04

まず渡された住所の中に、containsで〇〇県〇〇市という文字列データが2600件ほど入っているデータとforeachで照らしあわせて、見つかった場合はその〇〇県〇〇市という文字列を都道府県名 と 市町村区名に分解して、配列にして返してます。 分解には主に、http://dobon.net/vb/dotnet/vb2cs/mid.htmlで紹介されている関数を使っています。都道府県名で4文字なのはすべて「県」なので、4文字目に県があった場合と3文字目だった場合&「県」がなかった場合の処理で分けています。 さいしょからデータにしておく、ですか。そうですね、毎回処理をするよりはそちらのほうが良さそうです。〇〇県〇〇市のデータはもうあるので、それを分離したデータも作っておこうと思います。
thinca

2016/07/28 07:45

アルゴリズムの改善の方が効果は高いと思いますが、提示されているコードの範囲でできそうな最適化に、文字列の構築に StringBuilder を使う方法があります。 https://msdn.microsoft.com/ja-jp/library/system.text.stringbuilder(v=vs.110).aspx 文字列を毎回 += で構築するのは重いのでそういった際に使用します。参考にどうぞ。
kurosuke___

2016/07/28 09:42

thincaさん、ありがとうございます! とても参考になります!
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.30%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問