ファイルからデータを読み込んで計算式に当てはめるプログラム

タグの編集
投稿者 aaaa  (学生) 投稿日時 2009/11/19 01:04:48
テキストファイルからデータを読み込み、その値を式に当てはめて順次計算していくプログラムを作りたいのですが、
例えば、
   ファイル1(1列)    ファイル2(2列)
    700.15               700   0.99
    700.69               701   0.991
         ・           ・    ・
     ・           ・    ・


のように値が並んでる2つのファイルがあって
比を計算する式
   [y(x+1)-y(x)]× (i - x) + y(x)
に当てはめたいのですが、

・i=ファイル1の値(たとえば700.15)
・x=int(i) (iの小数点以下切り捨て)として

・y(x)     xの値がファイル2の1列目の値(例えば700)と一致するとき、
        それの右にある値(2列目・例えば0.99)を返す。

・y(x+1)   xの値に+1したものがファイル2の1列目の値(例えば701)と一致するとき、
        それの右にある値(例えば0.991)を返す。
このy(x) のようなプログラムはどのように組んだらよいでしょか?
投稿者 ?-?  (その他) 投稿日時 2009/11/19 01:59:36
二つのファイルじゃなく、一つのファイルで、1行だけ(700.15 700 0.99)の場合は出来ますか?

出来ていない場所をまずは一つずつ解決していきましょう。

ヒントとして、
配列を使う
ファイルを二回読み込む
とだけ書いておきます。

(計算は出来ますよね?)
投稿者 aaaa  (学生) 投稿日時 2009/11/19 03:23:34
返信ありがとうございます。
言われたどうりに1行×3列の一つのファイルで
できるかどうかチャレンジしてみたのですが詰まってしまいました。
Dim t() As System.IO.StreamReader
t = My.Computer.FileSystem.OpenTextFileReader("C:\プログラミング\8.txt")
としたら
型System.IO.TextReaderの値を型System.IO.StreamReaderの1次配列に変換できません
というエラーが出てきます。

配列は独学で勉強したところなので根本的なとこで間違ってるかもしれませんが・・・
投稿者 (削除されました)  () 投稿日時 2009/11/19 04:07:51
(削除されました)
投稿者 流れ者  (その他) 投稿日時 2009/11/19 04:10:56
こんばんは。

手元に環境が無いので、分かる範囲でお答えします。

>型System.IO.TextReaderの値を型System.IO.StreamReaderの1次配列に変換できません
>というエラーが出てきます。
これですが、

>Dim t() As System.IO.StreamReader
ここで、配列を宣言しているのに、

>t = My.Computer.FileSystem.OpenTextFileReader("C:\プログラミング\8.txt")
ここで、配列ではない値を入れようとしているからです。

テキストファイルから文字列を読み込もうとするなら、次のような方法があります。
Dim stringBuff As String           'ファイルから読み込んだ文字列を入れる変数  
Dim reader As System.IO.TextReader 'ファイルから文字列を読み込むためのIO変数  

'ファイルを読み込むためのIO変数を開く  
reader = My.Computer.FileSystem.OpenTextFileReader("C:\プログラミング\8.txt")

'ファイルの内容を一行読み込む  
stringBuff = reader.ReadLine()

'ファイルの内容が終わるまで繰り返す  
Do While stringBuff Is Not Nothing
       '    :  
        'やりたい処理を行う  
        '    :  

    '次の行を一行読み込む。  
  stringBuff = reader.ReadLine()

Loop

reader.Close() 'IO変数を閉じる  


 
投稿者 ?-?  (その他) 投稿日時 2009/11/19 04:12:20
まずは、配列に入れるのじゃなく、一行読み込みしましょう。
その後で、一行の内容を切り分けて、配列に入れてみましょう。

これが出来れば残りはもう独力で出来るでしょう・・・たぶん・・・
投稿者 aaaa  (社会人) 投稿日時 2009/11/21 03:25:40
すいません いろいろ教えてもらった結果
 Dim reader As New IO.StreamReader("C:\プログラミング\データ.csv", System.Text.Encoding.GetEncoding("Shift-JIS"))
        Dim Items() As String                   'csvの各項目を表す関数
        Dim Line As String = reader.ReadLine()  'CSVの一行
        Dim a, b, c As String                   '波長1,波長2,レファ値 文字列
        Dim d, f, g As Decimal                  '波長1,波長2,レファ値 数値
        Dim h As Integer                        '波長1の少数以下切り捨て
        Dim i, j As Decimal
        Do While Line IsNot Nothing
            Items = Line.Split(",")             '一行を, (カンマ)で区切って項目ごとに分解

            a = Items(0)                        '波長1取得
            d = Val(a)                          '波長1を数値に変換
            b = Items(1)                        '波長2取得
            f = Val(b)                          '波長2を数値に変換
            c = Items(2)                        'レファ値取得
            g = Val(c)                          'レファ値を数値に変換
            h = Int(d)                          '波長1の少数以下切り捨てた値

            If h = f Then
                i = g

            End If

            If h + 1 = f Then
                j = g

            End If

            TextBox1.AppendText((j - i) * (f - h) + i & vbCrLf)
            Line = reader.ReadLine              '次の行を読み込む。
        Loop
        
        reader.Close()
という風に書いたんですけど結果は駄目だったです。
(h+1)がfと一致するときその対応するgを返すやり方がよくわかりません
教えていただけるとありがたいです。
投稿者 るしぇ  (社会人) 投稿日時 2009/11/21 04:17:36
最初のレスで解決するだけのヒントは出てるね。

波長1は1行目だけのデータを読んだ時点で置いておいて、
波長2はファイルの最後の行まで読まないと見つからないのでは?
提示されたコードは波長1も波長2も1行ずつ読もうとしてるね。

だから、先に波長2とそれに対応する数値だけファイルの最後まで
読み込んで配列に覚えておけば?ってことですね。
波長2と対応する数値を、横2列×縦ファイル行数分の配列に
全部入れておけば、ファイルを何度も読み直さなくてもいい
わけです。

それ以外は、人間がやる方法と同じで特に難しい内容って
ありませんよね?

波長1の1行目読む。
 波長2の1行目読む。波長1と比較。一致してたら波長1の2行目へ。
 波長2の2行目読む。波長1と比較。一致してたら波長1の2行目へ。
 …
 波長2の最終行読む。波長1と比較。一致してたら波長1の2行目へ。

波長1の2行目読む。
 波長2の1行目読む。波長1と比較。一致してたら波長1の3行目へ。
 波長2の2行目読む。波長1と比較。一致してたら波長1の3行目へ。
 …
 波長2の最終行読む。波長1と比較。一致してたら波長1の3行目へ。

波長1の3行目読む。
 波長2の1行目読む。波長1と比較。一致してたら波長1の4行目へ。
 波長2の2行目読む。波長1と比較。一致してたら波長1の4行目へ。
 …
 波長2の最終行読む。波長1と比較。一致してたら波長1の4行目へ。

あとは同じ処理が繰り替えされるのでループを使ってまとめれば
上の処理が5行ぐらいのプログラムにまとまりそうだね。
投稿者 aaaa  (社会人) 投稿日時 2009/11/21 05:57:23
すいません何度も
教えてもらった通りにやってみたのですがうまくいきませんでした。
以下のように書いたのですが何か根本的なとこで間違ってるのでしょうか。


 Dim reader As New IO.StreamReader("C:\プログラミング\2.txt", System.Text.Encoding.GetEncoding("Shift-JIS"))
        Dim file As New IO.StreamReader("C:\プログラミング\1.txt", System.Text.Encoding.GetEncoding("Shift-JIS"))
        Dim Items(2250, 1) As String
        Dim Line As String = file.ReadLine()            '波長2とレファ値読み込み
        Dim a As String = reader.ReadLine                '波長1読み込み
        Dim b, d, f, y As Decimal
        Dim c, i As Integer

        '波長2とレファ値を読み込んで配列に入れる
        Do While Line IsNot Nothing


            Items(2250, 1) = Line

            Line = file.ReadLine

        Loop
       

        i = -1
        '波長1を読み込んで少数以下切り捨てて一致する波長2のレファ値を返す
        Do While a IsNot Nothing

            b = Val(a)
            c = Int(b)
            Do Until i > 2249
                i = i + 1

                If c = Items(i, 0) Then
                    d = Items(i, 1)

                End If
                If c + 1 = Items(i, 0) Then
                    f = Items(i, 1)
                End If
            Loop


            a = reader.ReadLine()
            y = (f - d) * (b - c) + d
            TextBox1.AppendText(y & vbCrLf)

        Loop

        


        reader.Close()
        file.Close()
投稿者 るしぇ  (社会人) 投稿日時 2009/11/21 22:17:18
> 以下のように書いたのですが何か根本的なとこで間違ってるのでしょうか。
プログラムについて勉強してないんだったらそうなんじゃないの?
勉強してるならデバッグくらいしてください。ステップ実行で各変数を
確認した時に正しくデータが格納されていましたか?
投稿者 aaaa  (学生) 投稿日時 2009/11/26 01:33:23
波長2とそれに対応する数値だけファイルの最後まで読み込んで配列に覚えさせるのはどうしたらいいですかね。
投稿者 ?-?  (その他) 投稿日時 2009/11/26 07:31:52
> 波長2とそれに対応する数値だけファイルの最後まで読み込んで配列に覚えさせるのはどうしたらいいですかね。

文字通り、そのファイルを最後まで読み込んで、配列に入れるのですけど?
どこでダメなんですか?
1行読み込んで、読み込んだ内容を切り出して、波長2用の配列と、数値用の配列に書けばいいだけですよ?
それを最後まで繰り返すだけです。

切り出し方(分け方)がわからない?

それと、るしぇさんが
> 勉強してるならデバッグくらいしてください。ステップ実行で各変数を
> 確認した時に正しくデータが格納されていましたか?
と書かれていますが、それに対する回答は?
デバック実行してみましたか?

投稿者 流れ者  (その他) 投稿日時 2009/11/26 19:03:56
こんにちは。

コードが投稿されてから、時間がたっているので、
コードの間違いのヒントのみお伝えします。

1.配列の最初の要素に値が入っていない。
2.ある型の変数に別の型の変数を代入しようとしている。

この2点です。

切り出し方は、既に答えに近いものを、aaaaさんは自ら見つけています。
2009/11/20 18:25:40 に投稿したコードを解析してみてください。
投稿者 aaaa  (学生) 投稿日時 2009/11/26 21:37:09
やっとできました。
配列について勘違いしていたのが原因でいろいろこんがらがってしまったっぽいです。
終わってみればシンプルにできましたね。
いろいろと助言くださったみなさんにお礼申し上げます。
投稿者 あお  (社会人) 投稿日時 2009/11/26 22:22:00
完成したコードくらい乗せるのが礼儀だと思うんですが……
投稿者 ?-?  (その他) 投稿日時 2009/11/26 22:27:04
> 投稿者 あお   (社会人)   投稿日時 2009/11/26 13:22:00  
> 完成したコードくらい乗せるのが礼儀だと思うんですが…… 

んー、どうでしょうか?

コードを載せるのではなく、間違っていた部分を他の人にもわかりやすく結果をフィードバックするだけでもいいのだと、私は思いますよ。



投稿者 (削除されました)  () 投稿日時 2009/11/26 22:27:05
(削除されました)
投稿者 aaaa  (学生) 投稿日時 2009/11/27 00:11:32
すいません
完成するまで1週間以上かかったので、計算結果が上手くいった時うれしくて先に報告だけでもと思ったのですが失礼な行為だったようですね。

以下が完成したコードです。


 '実験で得られる波長(250.19,…etc)のファイル読み込み
        Dim reader As New IO.StreamReader("C:\プログラミング\2.txt", System.Text.Encoding.GetEncoding("Shift-JIS"))
        '企業から送られてきた波長(250~2500)とそれに対応するデータのファイル読み込み
        Dim file As New IO.StreamReader("C:\プログラミング\ファイル2.csv", System.Text.Encoding.GetEncoding("Shift-JIS"))
        '結果をcsvファイルに書き込み
        Dim Writer As New IO.StreamWriter("C:\キャリブレーション.csv")

        Dim items() As String                       'ファイル2の波長とデータを切り分けて入れる配列                                          
        Dim kk(2250, 1) As Decimal                  '上で切り分けたのををさらに入れる配列
        Dim Line As String
        Dim a As String
        Dim b, d, f, y As Decimal
        Dim c, i, j As Integer



        Line = file.ReadLine                    'ファイル2を1行読み込み
        a = reader.ReadLine                     '2を1行読み込み



        j = -1                                  'jの初期値

        'ファイル2を切り分けて配列に入る作業をファイルの最後まで繰り返す
        Do While Line IsNot Nothing
            items = Line.Split(",")
            d = Val(items(0))
            f = Val(items(1))

            'それをさらに2250×2行列の配列に入れる
            j = j + 1
            kk(j, 0) = d
            kk(j, 1) = f
            Line = file.ReadLine

        Loop




        '2(実験で得られる波長のファイル)を最後まで繰り返す
        Do While a IsNot Nothing
            b = Val(a)
            c = Int(b)                  '実験で得られる波長の小数点以下を切り捨てたもの
            i = c + 1                   '上の波長より1だけ大きい波長
            '計算式
            y = (kk((i - 250), 1) - kk((c - 250), 1)) * (b - c) + kk((c - 250), 1)
            '例:最初の250.19の場合 (kk(1,1)-kk(0,1))×(250.19-250)+kk(0,1)  = (0.967 -0.965)×0.19+0.965=0.96662

            TextBox1.AppendText(y & vbCrLf)     'テキストboxに追加




            a = reader.ReadLine
        Loop

        Writer.WriteLine(TextBox1.Text)         '上の結果をcsv形式で書き込む
        'ファイルを閉じる
        reader.Close()
        file.Close()
        Writer.Close()



以上のようになりました。
投稿者 るしぇ  (社会人) 投稿日時 2009/11/27 01:38:20
応用の利くツールにするには改良点は何箇所かありますが、
個人で使うレベルなら、入力と期待される出力との組合せで
テストして、結果がOKなら良いんじゃないでしょうか。

改良できる点としては、
・波長一覧データが250から歯抜け無しに+1ずつ2250個整列していないといけない。
(歯抜けや最小波長が300に変更になったり、順番が違うと正しいものが取得できない)
・仕様上、それでいいのか疑問なコードがある。
(Val関数で数値データを取得しているが、数値以外のデータが入っていた場合、
エラー表示すべきでは?)
・通常想定されるエラーに対する対処が無い。
(波長一覧データが2250個より少なかった場合。
実験で得られる波長2600のデータが来た場合。
実験で得られる波長200のデータが来た場合。)
・システムエラーに対する対処が無い。
(波長一覧データが2250個より多かった場合。
波長一覧データの1行にCSVデータの2列目がなかった場合。)
・コードが分かり難い。
(とりあえずの変数名のまま完成としている。
処理がブロック毎にまとまっていない(1行目読み込みのコードが2行目以降
読み込みのループの直前に無い。結果ファイルのOPENも同じく))


※ファイルの指定とかもダイアログ使って。。。とかは
多分、考えているけどすぐには実現できないからって
所だと思うので省いています。