質問をすることでしか得られない、回答やアドバイスがある。

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

新規登録して質問してみよう
ただいま回答率
85.47%
FORTRAN

FORTRAN(フォートラン)は科学時術計算に向いた手続き型プログラミング言語です。 並列計算の最適化が行いやすい特性上、数値予報および気候モデルなどの大規模な計算を行う分野のスーパーコンピュータで使われています。

配列

配列は、各データの要素(値または変数)が連続的に並べられたデータ構造です。各配列は添え字(INDEX)で識別されています。

Q&A

解決済

1回答

6536閲覧

fortranで,列の数が分からない表のデータを読み込みたい

epsilon

総合スコア2

FORTRAN

FORTRAN(フォートラン)は科学時術計算に向いた手続き型プログラミング言語です。 並列計算の最適化が行いやすい特性上、数値予報および気候モデルなどの大規模な計算を行う分野のスーパーコンピュータで使われています。

配列

配列は、各データの要素(値または変数)が連続的に並べられたデータ構造です。各配列は添え字(INDEX)で識別されています。

0グッド

1クリップ

投稿2021/10/29 12:59

編集2021/11/10 05:22

前提・実現したいこと

fortran で,表の形のデータを読みこんで配列に格納し,処理するプログラムを作っており,
読み取りの際に,行の数は固定で列の数が未知のデータに対応できるようにしたいと思っています。

入力データの表は以下のような感じになっており,(〇は数値)

見出し1 見出し2 見出し3 ・・・・・・・・大体30列前後,未知
〇   〇    〇   ・  ・  ・   
〇   〇    〇   ・  ・  ・ 
〇   〇    〇   ・  ・  ・ 
・   ・    ・
・   ・    ・  
・   ・    ・
約20万行,固定

発生している問題・エラーメッセージ

自分としては,ソースコードのように見出しと数値を別々に読みこんだ上で,
一つ一つの列をまとめて読み込みながら列の方向にdoループを回していき
iostatが負を示した時点を表の終わりと見なすようにしたいと思っていました。

ただそのやり方では,結果を確認しても,並びが全く原型をとどめておらず,うまく読みこめていない様です。

allocateを使う事も考えましたが,readする前に行列の大きさを把握できなければならず,その方法が思いつきませんでした。

他に何か良い方法はないでしょうか。
よろしくお願いします。

(ちなみに,可能であれば行,列ともに未知でも可能な方法があれば,
合わせて教えて頂けると助かります。)

該当のソースコード(抜粋)

fortran

1filename=a(p) 2 open(10, file=trim(filename)) 3 write(*,*), trim(filename) 4 5 l=0 6 do j=1, 100 7 !各項目の見出しの読み込み 8 read(10,*,iostat=ios) (head(i,j), i=1,1) 9 if(ios .lt. 0) exit 10 l=l+1 11 end do 12 write(*,*) l 13 14 15 m=0 16 do j= 1, 100 17 !データの読み込み 18     read(10,*,iostat=ios) (pix(i,j), i=1,size) 19 if(ios .lt. 0) exit 20 m=m+1 21 end do 22 write(*,*) m

該当のソースコード2

fortran

1program test 2 implicit none 3 real, allocatable :: pix(:, :) 4 integer :: nor, noc, nod, ip , i, j 5 character(len = 10), allocatable :: degree(:) 6 character(len = 99) :: buff 7 8 write(*,*) "input the angle you process" 9 read(*,*) buff 10 write(*,*)"length of the input data", len(buff) 11 12 open(10, file= "angle_list.txt") 13 write(10,*) buff 14 15 nod=0 16 ip=0 17 do while (ip < len(buff)) 18 ip = ip + 1 19 if (buff(ip:ip) == ' ') cycle 20 nod = nod + 1 21 do while (buff(ip:ip) /= ' ') 22 ip = ip + 1 23 end do 24 end do 25 26 !roop: do while(ip < len(buff)) 27 ! ip= ip + 1 28 ! if( buff(ip:ip)==" " ) then 29 ! nod= nod + 1 30 ! if( buff(ip+1:ip+1)==" " ) exit roop 31 ! end if 32 !end do roop 33 34 write(*,*)"variety of angle", nod 35 36 allocate(degree(nod)) 37 38 close(10) 39 40 open(10, file= "angle_list.txt") 41 read(10,*) (degree(i),i=1, nod) 42 43 write(*,*) "degree data" 44 do i=1, nod 45 write(*,*) degree(i) 46 end do 47 48 deallocate(degree) 49 50end program

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

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

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

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

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

curehoney

2021/10/29 15:44

列数は行ごとに違うんですかね?それとも1ファイル内では一定で、矩形に納まります?
epsilon

2021/10/29 22:40

はい,列数は全部の行で同じになります
guest

回答1

0

ベストアンサー

縦横のデータ数を知ったうえで、そのサイズに allocate してデータを一気に読み込むのが基本ですので、それに従うことにします。

ここでは、入力データの見出し語が空白区切りでデータと同数、数値データは矩形で、ファイル末尾にフッターのようなものが無いと仮定します。

まず見出し語行を文字列バッファーに読み込んで、内部ファイルとして空白区切りを探して見出し語数を数えます。

次にデータ行数を知るため、ファイル末まで空読みして行数を数えます。

これでデータ数の縦横が分かったので、配列を割り付け、ファイルをリワインドして先頭に巻き戻し、配列一括読み取りします。

注意点:Fortran は column first なので、一気読みすると配列を転置した形になります。

fortran

1program test 2 implicit none 3 real, allocatable :: pix(:, :) 4 integer :: nor, noc, ip 5 character(len = 10), allocatable :: head(:) 6 character(len = 999) :: buff 7 open(10, file = 'test.dat') 8 9 read(10, '(a)') buff 10 11 noc = 0 12 ip = 0 13 do while (ip < len(buff)) 14 ip = ip + 1 15 if (buff(ip:ip) == ' ') cycle 16 noc = noc + 1 17 do while (buff(ip:ip) /= ' ') 18 ip = ip + 1 19 end do 20 end do 21 print *, 'no. of columns', noc 22 23 24 nor = 0 25 do 26 read(10, *, end = 99 ) 27 nor = nor + 1 28 end do 2999 print *, 'no. of rows', nor 30 31 32 allocate(head(noc)) 33 allocate(pix(noc, nor)) ! column first なので転置で一気読み込みします 34 35 rewind(10) 36 read(10, *) head 37 read(10, *) pix 38 39 40 block 41 character(len = 20) :: fmt 42 print *, head 43 write(fmt,'(a, i0, a)') '(', noc, 'f10.6)' 44 print fmt, pix 45 end block 46end program test 47
aaaa bb c ddddd eeeee 1.0 2.0 3.0 4.0 5.0 0.999 0.888 0.777 0.666 0.555 1 2 3 4 5

・結果

no. of columns 5 no. of rows 3 aaaa bb c ddddd eeeee 1.000000 2.000000 3.000000 4.000000 5.000000 0.999000 0.888000 0.777000 0.666000 0.555000 1.000000 2.000000 3.000000 4.000000 5.000000

投稿2021/10/30 03:50

編集2021/10/30 04:15
curehoney

総合スコア249

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

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

epsilon

2021/11/01 03:42

ありがとうございます。
epsilon

2021/11/10 05:55 編集

すみません,追加でお聞きしたいのですが, 回答のコードの10行目以降の,列の数を数える処理をそのまま利用して, 画面に 45 60 75 のように入力した角度のデータの数を把握し,角度を配列に格納したいと思い, 質問欄のソースコード2のように行ったのですが, 以下の出力結果のように,データを3つ入力した場合でも 先頭の1つしか読み取れていないようです 色々試したのですが,何か解決方法などあればよろしくお願いします. input the angle you process 45 60 75 ←※画面入力 length of the input data 99 variety of angle 1 degree data 45
curehoney

2021/11/27 11:43

質問に気づかなくてすみません。 今のままですと、変数が1個しかないので最初の一つしか読み込まれません。 全体をループするか、変数を配列に直して入力をため込んでおいて、ループすることが考えられます。 簡単な例で試してみるのが良いかと思います。
epsilon

2021/12/24 09:10

返信が遅れ申し訳ありません。 ありがとうございます。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.47%

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

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

質問する

関連した質問