今、VisualStudio 2005 C#でデータを読み込んで、グラフにプロットするプログラムを組んでいます。読み込むデータは1行が16項目のテキストファイルです。プロットまでの手順は以下のようになっています。
------------------------------------------------------
(1)予めテキストデータを全て行単位で配列に格納しておく
(2)プロットするデータの条件を決定(任意)
(3)プロット処理開始(ボタンクリックイベント)
(4)1行目から最終行まで探索し、
条件と一致するデータが見つかれば、行データを分割して対象データを描画
------------------------------------------------------
現状では、ボタンクリックイベントである(3)、(4)の処理に数分間掛かってしまいます。予め配列に格納すれば、(ボタンクリックイベントの際の)ハードディスクへのアクセス時間が短縮されると考え、このようなアルゴリズムを組んだのですが、より効率の良い方法があれば教えて頂けないでしょうか。
よろしくお願いします。
No.4ベストアンサー
- 回答日時:
>(4)1行目から最終行まで探索し、
いわゆるシーケンシャルサーチのようですが
10万行あれば10万回の検索が発生し
条件が100個あるとするなら1000万回の比較が発生しますよね?
2分探索を使えばLog2(10万)=16.6
つまり17 * 100 = 1700回の比較で済みます。
(1)予めテキストデータを全て行単位で配列に格納しておく
(2)プロットするデータの条件を決定(任意)
(3)配列のデータをソート
(4)プロット処置開始
(5)2分探索で目的のデータを検索
(6)一致するものがあれば描画
あと6(描画)はネックにはなっていませんか?
もしボトルネックになっているとするなら毎回描画するのではなく
バックサーフェースを作り(System.Drawing.Graphicsを別に作成)
そこで全てを描画しきってから
Graphics.DrawImageで転送すると速くなるでしょう。
ボトルネックを調べるにはQueryPerformanceCounterを使ってください。
その処理に何クロックかかっているかがわかります。
http://www.divakk.co.jp/aoyagi/csharp_tips_trace …
ご返答ありがとうございます。
皆さんのアドバイスを取り入れた上で、その成果をQueryPerformanceCounterで確認したいと思います。
No.8
- 回答日時:
補足:
UNIX C、Windows C、Windows VB でBLoad の書き方もそれぞれ。
C# のそれもまた違うでしょう。
要は、アイデアを提示したということ。
「前処理と本処理の2段構えだと、いかようにも本処理を最適化しやすいのでは?」という提案です。
No.7
- 回答日時:
C言語で書いたのは Sony の News が発売された頃。
ですから、そのソースはないです。
ただ、Windows 3.1 の頃に書いたのは残っています。
/*---------------------------------------------------------
* bsave
*---------------------------------------------------------*/
#include <stdio.h>
FILE *file_open(char *, char *,char *);
size_t bsave(fname, vp, recsize, dir)
char *fname;
void *vp;
size_t recsize;
char *dir;
{
FILE *fp;
if (fp = file_open(fname, "wb", dir)) {
recsize = fwrite(vp, recsize, 1, fp);
fclose(fp);
} else
ferr("bsave: セーブエラー", fname, 1);
return(recsize);
}
bload は、全く、この逆なので割愛します。
/*------------------------------------------------------------
* t_load
*------------------------------------------------------------*/
#include <string.h>
#include <memory.h>
typedef struct{
char member1[21];
char member2[21];
} TEST1;
typedef struct{
char member1[21];
char member2[21];
} TEST2;
size_t bsave(char *, void *, size_t. char *);
size_t bload(char *, void *, size_t. char *);
main()
{
TEST1 T1;
TEST2 T2;
memset(T1.member1, 0, 21);
・・・・
struct(T1.member1, "T1.member1");
・・・・
bsave("test1.bin", &T1, sizeof(T1), "TMP");
・・・・
lset(T1.member1, "");
・・・・
bload("test.bin", &T1, sizeof(T1), "TMP");
・・・・
putf("&---+----1----+----&0", T1.member1);
・・・・
return(0)
}
[実行結果]
T1.member1
T1.member2
総称的なポインタを使って、BASICのBLOADとBSAVEを再現。(昔は、かかる関数があった)
内容的には、update_bfile関数を書き込みと検索に分け、レコード1とのアクセスに限定。
30MZという当時のボロパソコンでもRAMディスクですと0.11秒でセーブとロードできたとあります。
なお、lset、putf などは自作ライブラリかも知れません。
とにもかくにも10数年前の話しです。
No.6
- 回答日時:
#2です。
ごめんなさい。
ArrayListだと部分一致が難しいを忘れてました。
で、話が戻る形になるのですが、以下のコードでやってみても無理ですかね。
string[] data = { "aaaa", "bbbaaa", "ababab", "asdfaa", ";lkja" };
foreach (string str in Array.FindAll(data, delegate(string s) {return s.IndexOf("aaa") != -1;}))
{
Console.WriteLine(str);
}
多分、該当する列を取得できると思うのですが・・・
だめだったら、格納先をDataTableにしてSelectメソッドで拾ってくるしか考え付きません。
DataTableのSelectメソッド使用のサンプル※MSDN
http://msdn2.microsoft.com/ja-jp/library/det4aw5 …
ごめんなさい。
No.5
- 回答日時:
#2です。
説明ありがとうございます。
状況はわかりました。
(1)は他でも使用するので今回は別として考えてます。
(4)の検索が早くなれば問題ないということですね。
(3)のボタンクリック処理で何をやっているかわからないので何とも言えないのが現状です。
まず、何の配列にデータを格納しているのでしょう。
String配列ですかね。
String配列の内部を検索する場合ですが、配列の数分の文字列を1行1行LOOPして探さなければいけません。
そんなことをしていたら時間が掛かるのは当たり前です。
なので、格納する配列をString配列からArrayListに変更してみてはどうでしょう。
予想ではかなりの時間短縮になると思います。
ArrayList内の検索を行う(中段辺りに記述)
http://dobon.net/vb/dotnet/programing/icomparer. …
どうですかね・・・^^;
この回答への補足
ArrayListを導入してみました。都合上、(文字列の)部分検索を行いたいんですが、行えるような情報がありません…やはり不可能なんでしょうか。
補足日時:2007/08/03 14:05おっしゃる通り、使っているのはString配列です。やっぱり時間がかかる要因はここだったんですかね。早速ArrayListに移行してみようと思います。
No.3
- 回答日時:
BLoad、BSave なんて便利な関数はないですから自作することになります。
これは、いわゆる バイナリロード、バイナリセーブから命名したものです。
CとVBとで作った経験があります。
現在は、Access で同様のことをしています。
' --------------------------------------------------------------------------------
' 構造体変数 MyMenu を Menu.ini に保存
' --------------------------------------------------------------------------------
Private Function BSave(ByVal FileName As String, ByRef MyMenu As MENU) As Boolean
On Error GoTo Err_BSave
Dim isOK As Boolean
Dim intFreeFile As Integer
isOK = True
intFreeFile = FreeFile
Open FileName For Random As intFreeFile Len = Len(MyMenu)
Put #intFreeFile, 1, MyMenu
Exit_BSave:
On Error Resume Next
Close #intFreeFile
BSave = isOK
Exit Function
Err_BSave:
isOK = False
Resume Exit_BSave
End Function
A4で10ページ近い Menu.ini を呼び込んで解析し変数に取り込むなんてことをしていたら大変です。
そこで、予め<解析し変数に取り込む>は済ませておく訳です。
この場合、検索が最も簡単・高速になるように構造体変数化します。
C#は存じませんが、Cであれば当然に出来たこと。
まあ、C#も不可能ではないと思います。
' -----------------------------------
' Menu.bin または Menu.ini をロード
' -----------------------------------
If FileExists("Menu.bin") Then
StopNow = Not BLoad("Menu.bin", MyMenu)
End If
これが、実際に取り込んでいるコード部分です。
構造体変数はこれで出来上がりますので、後は、利用するだけ。
ディスクアクセスもないので超高速になります。
以下は、解析前の Menu.ini です。
この形式を幾ら工夫しても、解析する限りでは限度があると思います。
* +----------------------> アイコンの説明文
* | +--------------> アプリケーション名
* | | +----------> アイコンの場所
* | | | +--> 詳細表示の説明文
* ---------------|-------|---|-------|------------------------
* ----+----1----+----2----+----3--
0-0-0=Icons\Large\売上伝票.ico ' 大きいアイコンの場所
0-0-1=Icons\Small\form.ico ' 小さいアイコンの場所
0-0-2=売上伝票入力 ' アイコンの説明文
0-0-3=F ' F、R、E
0-0-4=売上伝票 ' アプリケーション名
0-0-5=売上伝票フォームを開きます。 ' 詳細表示の説明文
* ------------------------------------------------------------
0-1-0=Icons\Large\仕入伝票.ico
0-1-1=Icons\Small\form.ico
0-1-2=仕入伝票入力
0-1-3=F
0-1-4=仕入伝票
0-1-5=仕入伝票フォームを開きます。
* ============================================================
1=月次処理(&M) ' 最大16桁
* ============================================================
* +----------------------> アイコンの説明文
* | +--------------> アプリケーション名
* | | +----------> アイコンの場所
* | | | +--> 詳細表示の説明文
* ---------------|-------|---|-------|------------------------
* ----+----1----+----2----+----3--
1-0-0=Icons\Large\売上伝票.ico ' 大きいアイコンの場所
1-0-1=Icons\Small\form.ico ' 小さいアイコンの場所
1-0-2=売上伝票入力 ' アイコンの説明文
1-0-3=F ' F、R、E
1-0-4=売上伝票 ' アプリケーション名
1-0-5=売上伝票フォームを開きます。 ' 詳細表示の説明文
* ------------------------------------------------------------
1-1-0=Icons\Large\仕入伝票.ico
1-1-1=Icons\Small\form.ico
1-1-2=仕入伝票入力
1-1-3=F
1-1-4=仕入伝票
1-1-5=仕入伝票フォームを開きます。
END
申し訳ないんですが、VBの知識がほとんど無いのでちょっと読みづらいと言うのが正直なところです。
大変厚かましいお願いなんですが、もし可能ならばCで記述したコードを見せて頂けないでしょうか?
No.2
- 回答日時:
考え方が変わってしまうのですが・・・
(1)を一番最初に行う理由は?
もし、無いのであれば、テキストデータを読み込みながら対象文字列がその1行に存在するか確認するロジックの方が良いと思うのですが。
(2)をやって(3)を押してから(1)と(4)を一緒に実行。
現在のままだとボタンをクリックされなくてもテキストデータを配列に格納しているから無駄かなと・・・^^;
1行ずつテキストデータを読み込むサンプル(真ん中辺りから・・・)
http://dobon.net/vb/dotnet/file/readfile.html
文字列内に対象文字列が存在するか検索する方法
http://jeanne.wankuma.com/tips/string/indexof.html
まぁ、VBプログラマーの言うことなので間違っているかもしれませんけど。
ご返答有難う御座います。
(1)を最初に行う理由は、ボタンクリックイベントでのHDへのアクセスを短縮するためです。そして、全てのデータを読み込む理由は別にあります(説明が不足してましたね)。
このプログラムは、データをグラフにプロットして可視化することで、データの特性を見るプログラムで、一旦実行すると何度もプロットを繰り返すことになるんです。ですから、プロットの度に探索を繰り返すよりも、予め全データを読み込んでおいた方が効率的だと考えたんです。ですから(3)(4)が速ければ、(1)にどれだけ時間が掛かっても構わないんです。
説明不足ですみませんでした。
No.1
- 回答日時:
>予めテキストデータを全て行単位で配列に格納しておく・・・
これが許されるのならば・・・。
一介の服飾デザイナでプログラマではありません。
が、昨今は、デザイナでもCADも操作しなきゃならないしフロントエンドも開発しなきゃ務まりません。
さて、注文データとCAD内のデータを付き合わせるには実に多くの比較計算が必要。
そのようなデータをオラクルやSQL Serverに登録していたら滅茶苦茶に時間がかかります。
C言語で組んでも1オーダ90秒が限界。
しかし、たった一つの構造体変数で1レコードで記録しておけば BLoad、BSave 関数を使えば一発。
処理過程でのディスクアクセスはゼロに抑えることができます。
この場合、90秒という計算時間は0.01秒以内に短縮することが出来ました。
ある程度のサイズのデータベースも構造体変数にすることも可。
まあ、素人の考えです。
ご返答有難う御座います。
構造体に全てのレコードデータを入れるということですか?
また、BLoad、BSave関数という名前は初めて聞くのでよく分からないのですが、言語は何でしょうか?
こっちも素人なんで…よろしくお願いします。
お探しのQ&Aが見つからない時は、教えて!gooで質問しましょう!
関連するカテゴリからQ&Aを探す
おすすめ情報
- ・漫画をレンタルでお得に読める!
- ・人生のプチ美学を教えてください!!
- ・10秒目をつむったら…
- ・あなたの習慣について教えてください!!
- ・牛、豚、鶏、どれか一つ食べられなくなるとしたら?
- ・【大喜利】【投稿~9/18】 おとぎ話『桃太郎』の知られざるエピソード
- ・街中で見かけて「グッときた人」の思い出
- ・「一気に最後まで読んだ」本、教えて下さい!
- ・幼稚園時代「何組」でしたか?
- ・激凹みから立ち直る方法
- ・1つだけ過去を変えられるとしたら?
- ・【あるあるbot連動企画】あるあるbotに投稿したけど採用されなかったあるある募集
- ・【あるあるbot連動企画】フォロワー20万人のアカウントであなたのあるあるを披露してみませんか?
- ・映画のエンドロール観る派?観ない派?
- ・海外旅行から帰ってきたら、まず何を食べる?
- ・誕生日にもらった意外なもの
- ・天使と悪魔選手権
- ・ちょっと先の未来クイズ第2問
- ・【大喜利】【投稿~9/7】 ロボットの住む世界で流行ってる罰ゲームとは?
- ・推しミネラルウォーターはありますか?
- ・都道府県穴埋めゲーム
- ・この人頭いいなと思ったエピソード
- ・準・究極の選択
デイリーランキングこのカテゴリの人気デイリーQ&Aランキング
-
VBA 変数名に変数を使用したい。
-
エクセルでXY座標に並べられた...
-
配列の中の最大値とそのインデ...
-
複数のtextboxの処理を一括で行...
-
グラフの「項目軸ラベルに使用...
-
配列のペースト出力結果の書式...
-
VBA Dowhile 判断条件に動的配...
-
VB6のメモリ解放に関して
-
Excel2010のinputboxで複数デー...
-
VB6からの移行したいけど、VB.N...
-
構造体配列の特定のメンバーをF...
-
C#でbyte配列から画像を表示さ...
-
Excelのメモリ(配列)の上限は2G...
-
vba フィルター 複数条件 3つ以...
-
pictureboxの名前を変数で設定...
-
COBOLの基本的な事なので...
-
VBScriptでCSVファイルを読み出...
-
VBAで配列引数を値渡しできない...
-
VBScript で ADO Streamオブジ...
-
Redim とEraseの違いは?
マンスリーランキングこのカテゴリの人気マンスリーQ&Aランキング
-
VBA 変数名に変数を使用したい。
-
C#でbyte配列から画像を表示さ...
-
vba フィルター 複数条件 3つ以...
-
エクセルでXY座標に並べられた...
-
Dir関数で読み取り順を操作でき...
-
Excel2010のinputboxで複数デー...
-
構造体配列の特定のメンバーをF...
-
Redim とEraseの違いは?
-
配列のペースト出力結果の書式...
-
COBOLの基本的な事なので...
-
大量の変数を定義するにはどう...
-
DBから取得した値を配列へ代入する
-
EXCEL VBAの課題です
-
VBScriptでCSVファイルを読み出...
-
VBAでMODE関数をつくる
-
配列の中の最大値とそのインデ...
-
定数配列の書き方
-
構造体配列内の文字列検索のよ...
-
CheckBoxの配列化
-
Excelのメモリ(配列)の上限は2G...
おすすめ情報