アプリ版:「スタンプのみでお礼する」機能のリリースについて

rubyで2次元配列あるいはさらに高次元配列を読み込む方法、および書き込む方法について例を上げて説明していただけると助かりますが。
2次元配列の形式はちょうどエクセルのスプレッドシートと同じです。
フォートランだったら次のような感じです。これのruby版ということですが。
open(10,file='...')
do j=ny,1,-1
read(10,*) (x(i,j),i=1,nx)
enddo
close(10)

ちなみにperlやCだとどうなるでしょうか。

よろしくお願いします。

A 回答 (5件)

> 配列の名前aryですが、どのようなサイズ・次元かを予め指定する必要はないのでしょうか。


>rubyではその必要はないのでしょうか。Cなどもそうでしょうか。

いわゆるスクリプト言語といわれるもの(動的言語)は必要ありません(ruby, python, perlなど)
C,Javaなど静的言語は宣言が必要です(動的メモリ管理もできると思いますが要素数がきまっているなら無駄なことはやらないと思います)
このあたりは、各言語の入門サイトなどで文法を確認されるのが良いかと。


No.2回答欄の内容でrubyの3次元プログラムを書いてみました。
※rubyでは多次元配列は無いので、配列の配列の配列という構造になります。
※2次元の場合は、NZのループを削除してください。
※配列の添え字は1ではなく0から始まります。
※ソース行頭は段付けの為、全角スペースになっています。

---sample.csv---
22.4, 23.5, 23.1, 22.3
22.1, 24.5, 23.3, 26.7
21.2, 24.2, 22.1, 24.1
12.4, 13.5, 13.1, 12.3
12.1, 14.5, 13.3, 16.7
11.2, 14.2, 12.1, 14.1
2.4, 3.5, 3.1, 2.3
2.1, 4.5, 3.3, 6.7
1.2, 4.2, 2.1, 4.1
----------------

---test.rb---
NZ = 3
NY = 3
NX = 4

a3 = Array.new # 3次元用配列作成

# 読み込み
File.open("sample.csv") do |f|
 NZ.times.each do # NZ回ループ
  a2 = Array.new # 2次元用配列作成
  (NY-1).downto(0).each do |j| # j = NY-1,NY-2,…,1,0でループ
   f.gets.chomp.split(/\s*,\s*/).each_with_index do |elm, i|
#                    # elm = ファイルから読み込んだ
#                    #    1行中のカンマ区切りの各要素
    a2[i] = Array.new if a2[i].nil? # a2[i]が空なら1次元配列を代入
    a2[i][j] = elm.strip.to_f #    elmからスペースを削除し数値化して代入
   end
  end
  a3.unshift(a2) # a2をa3の先頭の要素として挿入
 end
end



# 表示
p a3

#[[[1.2, 2.1, 2.4],
# [4.2, 4.5, 3.5],
# [2.1, 3.3, 3.1],
# [4.1, 6.7, 2.3]],
# [[11.2, 12.1, 12.4],
# [14.2, 14.5, 13.5],
# [12.1, 13.3, 13.1],
# [14.1, 16.7, 12.3]],
# [[21.2, 22.1, 22.4],
# [24.2, 24.5, 23.5],
# [22.1, 23.3, 23.1],
# [24.1, 26.7, 22.3]]]

puts
puts "a3[0][3][1] = #{a3[0][3][1]}"# a3[0][3][1] = 6.7
puts "a3[1][3][1] = #{a3[1][3][1]}"# a3[1][3][1] = 16.7
puts "a3[2][3][1] = #{a3[2][3][1]}"# a3[2][3][1] = 26.7



# 書き込み
File.open("sample2.csv","w") do |f| # 書き込みファイルオープン
 (NZ-1).downto(0).each do |k| #   k= NZ-1,NZ-2,…,1,0 でループ
  (NY-1).downto(0).each do |j| #  j= NY-1,NY-2,…,1,0 でループ
   line = Array.new
   NX.times.each do |i| #     i = 0,1,…,NX-2,NX-1 でループ
    line.push(a3[k][i][j].to_s)# a3の要素を文字列にして配列lineに追加
   end
   f.puts line.join(', ')#     lineの要素をカンマで繋げた1行にして出力
  end
 end
end
-------------
    • good
    • 0
この回答へのお礼

回答ありがとうございます。
fortranを書きます。sample.csvの内容をそのままsample2.csvに移すというだけですが。(動作確認)
parameter(nx=4,ny=3,nz=3)
dimension f(nx,ny,nz)

open(10,file='sample.csv')
do k=nz,1,-1
do j=ny,1,-1
read(10,*) (f(i,j,k),i=1,nx)
enddo
enddo
close(10)

open(10,file='sample2.csv')
do k=nz,1,-1
do j=ny,1,-1
write(10,'(10f8.2)') (f(i,j,k),i=1,nx)
enddo
enddo

stop
end

rubyでは多次元配列がないということでそのような考え方が難しいように思いましたが、実はすべての言語はそのような仕様になっているのかもしれませんが。多次元配列はないということですが、a3[k][i][j]というような表記はあり、というところがちょっと理解しづらいのですが。
なお、早速rubyで実行して動作の確認を行いました。やっぱり難しいですね。rubyのパターンは読んで、切り分けるという動作のように思います。fortranは配列を1つづつ読んで行くというイメージですが、rubyやperlでは切り分ける(chomp)という動作があるのでそこが慣れないですが。

お礼日時:2016/03/27 21:48

nx とか ny はどうやって与えているんだろう. ファイルを読み込む前に nx や ny がわかっているなら, x(:,:) を allocatable で宣言し nx と ny がわかった時点で allocate すれば「データが配列に収まり切れないとサイズを変更して再度コンパイル・実行」とはしなくていいね.



ちなみに Perl で 2次元なら
open my $fh, '<', 'filename';
@ary = reverse map { chomp; [split /\s*,\s*/]; } <$fh>;
close $fh;
の 3行 (読み込み自体は 1行) で終わる.
    • good
    • 0
この回答へのお礼

回答ありがとうございます。nx,nyは与えなくてもいいというのが理想です。読んだ結果、逆にnx,nyの値を出力してくれるというようなものですが。なお、データとしてはnx,nyがわかるような並びにはなっているということですが。
他の方法ですが、データの先頭にヘッダーとして書いておき、それを先に読んで、それに従ってデータを読むという方法はあると思いますが。rubyもperlもコンパイルしないインタープリターの言語ですから特にその方向で問題はないと思います。ただし、ヘッダーに書くのは実は少しの不都合があるのですが。
perlスクリプトは、1レコード読んで、","での区切りでバラバラにして配列化するというところまではわかる気がします。いつまでたってもperlには慣れません。

お礼日時:2016/03/27 19:50

Fortran の「並びによる入力」を本気で「まじめに実装する」と, たとえ ruby や Perl であってもめっちゃ大変ですよ. 例えば, 1行のデータが nx個でなかった場合にどのような処理になるか理解できていますか? あるいは, 例えば (nx = 4 として)


2*1.0, , 5.0
という行があったらどのように入力されるかわかっていますか?

あと, その「3次元」の場合で k=3 というのはどこから出てくるのですか?
    • good
    • 0
この回答へのお礼

回答ありがとうございます。
絶対に担保されている条件として、数値のデータであるということと空白はないということです。従って2*1.0, , 5.0というようなことを心配して例外処理を講じる必要はありません。”1行のデータがnxでない場合”、というのは、nxだったり、nx-1であったり行ごとにまちまちということでしょうか。それも想定していません。1行内のカラム数は行ごとに一定です。
しかしnx=100を前提としてそれだけしか対応できないと思っているプログラムでnx=99とか101のデータを読めるかという問題はあります。そこはフレキシブルに読めるプログラムだったら便利です。データごとにプログラムを変更しなくて済むからですが。そのようなことは可能でしょうか。

3次元配列のデータでは2次元データ(紙と同じ)が縦方向に何枚も重なっているというイメージです。だからK=1が1枚目,,K=3は3枚目です。その切れ目を示すために書いてあるだけであり、実際のデータにはないです。大きなループが外側に1つ回っているということです。

お礼日時:2016/03/26 05:27

「さらに高次元配列」は既に #1 で指摘されているようにデータの形式がまったくわからないので無視して, 2次元の場合でちょっと確認.



・添え字の最小値は 1 のままですか? それとも 0 にしていいですか?
・j は大きい方から小さい方へと減らすのですね?
・どこまでまじめに実装しますか?
    • good
    • 0
この回答へのお礼

回答ありがとうございます。さらに高次元は別途ということで2次元から行きたいと思います。
具体的に3×4の2次元を考えます。
2.4, 3.5, 3.1, 2.3
2.1, 4.5, 3.3, 6.7
1.2, 4.2, 2.1, 4.1
というデータを
a(1,3),a(2,3),a(3,3),a(4,3)
a(1,2),a(2,2),a(3,2),a(4,2)
a(1,1),a(2,1),a(3,1),a(4,1)
というように読みます。a(4,2)は6.7が入っています。

このデータ読み込み部は、読み込み後、様々な処理の基本となるため、100%の確実さを担保したいと思っています。よろしくお願いします。

なおさらに高次元と言っても3次元までですが、配列a(i,j,k)とするとデータはこの2次元のシートがこのままの縦に連続的に積み重なっているというイメージです。
2.4, 3.5, 3.1, 2.3 k=3
2.1, 4.5, 3.3, 6.7
1.2, 4.2, 2.1, 4.1
2.6, 3.5, 3.1, 2.3 k=2
2.1, 4.5, 3.3, 6.7
1.2, 4.2, 2.1, 4.1
2.7, 3.5, 3.1, 2.3 k=1
2.1, 4.5, 3.3, 6.7
1.2, 4.2, 2.1, 4.1

よろしくお願いします。

お礼日時:2016/03/24 21:10

> 2次元配列の形式はちょうどエクセルのスプレッドシートと同じです。



というのが具体的にどの様なものかわからないのですが
以下の様だとすると
---sample.csv---
1,2,3,4,5
11,12,13,14,15
111,112,113,114,115
------------------

プログラムは以下となります。
Fortranは知らないので動作に勘違いがありましたらスミマセン。
・CSVライブラリは敢えて使用していません
・インデント(段付け)の為、行頭に全角スペースを使用しています。
---test.rb---
require 'pp' # 表示で使用

ary = Array.new # 配列用変数

# 読み込み
File.foreach("sample.csv") do |rows| # rowsにファイルから1行代入
 ary << rows.chomp.split(',') " rowsの改行コード削除、カンマで分割したものをaryに追加
end

# 表示
pp ary
# [["1", "2", "3", "4", "5"],
#  ["11", "12", "13", "14", "15"],
#  ["111", "112", "113", "114", "115"]]


# 書き込み
File.open("sample2.csv","w") do |file| #書き込み用ファイルオープン
 ary.each do |rows| # 各ary[n]をrowsに代入
  file.puts rows.join(',') " # 各ary[n][m]をカンマでくっつけて一行として出力
 end
end
----------------


> さらに高次元配列を読み込む方法

データのフォーマットをご提示いただいた方がよいかと。
    • good
    • 0
この回答へのお礼

回答ありがとうございます。
この場合、配列の名前aryですが、どのようなサイズ・次元かを予め指定する必要はないのでしょうか。読み込む場合に既定のサイズや次元を超えたらエラーになるというのがFortranの基本的な考え方だと思います。データが配列に収まり切れないとサイズを変更して再度コンパイル・実行ということになりますが、rubyではその必要はないのでしょうか。Cなどもそうでしょうか。もちろんその方が柔軟に対応できるわけですが。

お礼日時:2016/03/24 21:20

お探しのQ&Aが見つからない時は、教えて!gooで質問しましょう!