今、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で質問しましょう!
似たような質問が見つかりました
- Excel(エクセル) 【VBA】指定フォルダに格納中のテキストファイルをエクセルで処理し結果のエクセルを新規フォルダに保存 1 2022/03/25 14:19
- Excel(エクセル) 【困っています】VBA 追加処理の記述を教えてください。 1 2022/08/25 22:54
- Visual Basic(VBA) 【前回の続き続きです、ご教示ください】VBAの記述方法がわかりません。 2 2022/08/24 20:49
- C言語・C++・C# [C言語] コメント文字列を無視して、数値データを読み込むプログラム部分について 5 2022/10/05 11:03
- Visual Basic(VBA) 【困っています2】VBA 追加処理の記述を教えてください。 2 2022/08/26 11:42
- Visual Basic(VBA) vbaについて 主に以下のような設定をしたいです。 Aブックの表の行数が20未満だったら Bブックの 1 2023/06/08 23:40
- Visual Basic(VBA) 3つのプロシージャをまとめたら実行時エラー発生で対応不能 6 2022/05/17 01:47
- Visual Basic(VBA) ファイル全てを .xlsm に変更したところ、プログラムが途中で落ちてしまっています 17 2022/12/07 12:03
- C言語・C++・C# C言語プログラム変更 2 2022/12/21 15:03
- Excel(エクセル) 非表示にしたい行をグループ化して折り畳み 4 2022/09/17 20:17
関連するカテゴリからQ&Aを探す
おすすめ情報
デイリーランキングこのカテゴリの人気デイリーQ&Aランキング
-
VBA 変数名に変数を使用したい。
-
DBから取得した値を配列へ代入する
-
C#でbyte配列から画像を表示さ...
-
構造体配列の一部初期化!!!
-
エクセルでXY座標に並べられた...
-
VB6で、一次元配列と二次元配列...
-
定数配列の書き方
-
配列の中の最大値とそのインデ...
-
オブジェクト名を変数で参照で...
-
配列の要素がすべてカラかどう...
-
vba フィルター 複数条件 3つ以...
-
Dir関数で読み取り順を操作でき...
-
ActiveReports(アクティブレポ...
-
VB.NETの配列にExcelから読み込...
-
VBで配列に格納されているデー...
-
8bitインデックス画像の入出力方法
-
Redim とEraseの違いは?
-
VBでの配列をEXCELに出力する方法
-
EXCEL VBA 配列デー...
-
Excel2010のinputboxで複数デー...
マンスリーランキングこのカテゴリの人気マンスリーQ&Aランキング
-
VBA 変数名に変数を使用したい。
-
vba フィルター 複数条件 3つ以...
-
C#でbyte配列から画像を表示さ...
-
Excel2010のinputboxで複数デー...
-
エクセルでXY座標に並べられた...
-
構造体配列の特定のメンバーをF...
-
定数配列の書き方
-
コンボボックスのインデックス...
-
OutOfMemoryExceptionの回避策...
-
Dir関数で読み取り順を操作でき...
-
CheckBoxの配列化
-
構造体配列内の文字列検索のよ...
-
COBOLの基本的な事なので...
-
Redim とEraseの違いは?
-
VBAで配列引数を値渡しできない...
-
2次元配列の初期値
-
配列の中の最大値とそのインデ...
-
大量の変数を定義するにはどう...
-
VB6からの移行したいけど、VB.N...
-
VB6のメモリ解放に関して
おすすめ情報